diff options
author | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2014-05-18 00:37:10 +0000 |
---|---|---|
committer | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2014-05-18 00:37:10 +0000 |
commit | 63fee735002b34d37598d4830ef35073202dda58 (patch) | |
tree | b6d50c223905f199bdd237b639109d4c0dcde0f1 /missing | |
parent | ddd155842fb4fd96a028836d926bae7501cbd985 (diff) | |
download | ruby-63fee735002b34d37598d4830ef35073202dda58.tar.gz |
* configure.in: Check nextafter() availability.
* include/ruby/missing.h (nextafter): New optional declaration.
* missing/nextafter.c: New file.
* numeric.c: Float#next_float and Float#prev_float implemented.
[ruby-core:62562] [Feature #9834]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@45982 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'missing')
-rw-r--r-- | missing/nextafter.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/missing/nextafter.c b/missing/nextafter.c new file mode 100644 index 0000000000..116a0d376b --- /dev/null +++ b/missing/nextafter.c @@ -0,0 +1,75 @@ +#include <math.h> +#include <float.h> + +/* This function doesn't set errno. It should on POSIX, though. */ + +double +nextafter(double x, double y) +{ + double x1, x2, d; + int e; + + if (isnan(x)) + return x; + if (isnan(y)) + return y; + + if (x == y) + return y; + + if (x == 0) { + /* the minimum "subnormal" float */ + x1 = ldexp(0.5, DBL_MIN_EXP - DBL_MANT_DIG + 1); + if (x1 == 0) + x1 = DBL_MIN; /* the minimum "normal" float */ + if (0 < y) + return x1; + else + return -x1; + } + + if (x < 0) { + if (isinf(x)) + return -DBL_MAX; + if (x == -DBL_MAX && y < 0 && isinf(y)) + return y; + } + else { + if (isinf(x)) + return DBL_MAX; + if (x == DBL_MAX && 0 < y && isinf(y)) + return y; + } + + x1 = frexp(x, &e); + + if (x < y) { + d = DBL_EPSILON/2; + if (x1 == -0.5) { + x1 *= 2; + e--; + } + } + else { + d = -DBL_EPSILON/2; + if (x1 == 0.5) { + x1 *= 2; + e--; + } + } + + if (e < DBL_MIN_EXP) { + d = ldexp(d, DBL_MIN_EXP-e); + } + + x2 = x1 + d; + + if (x2 == 0.0) { + if (x1 < 0) + return -0.0; + else + return +0.0; + } + + return ldexp(x2, e); +} |