summaryrefslogtreecommitdiff
path: root/missing
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-05-18 00:37:10 (GMT)
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-05-18 00:37:10 (GMT)
commit63fee735002b34d37598d4830ef35073202dda58 (patch)
treeb6d50c223905f199bdd237b639109d4c0dcde0f1 /missing
parentddd155842fb4fd96a028836d926bae7501cbd985 (diff)
* 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.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/missing/nextafter.c b/missing/nextafter.c
new file mode 100644
index 0000000..116a0d3
--- /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);
+}