November 22, 2007 nextafter | ||||
---|---|---|---|---|
| ||||
It seems nextafter doesn't work with DMD v1.023 on Win on real type, this is my implementation, it may be slow, but it seem to work (but lastbit_wrt_half must be changed if real changes its bit representation): /****************************************** Calculates the next representable value after x in the direction of y. If y > x, the result will be the next largest floating-point value; if y < x, the result will be the next smallest value. If x == y, the result is y. The FE_INEXACT and FE_OVERFLOW exceptions will be raised if x is finite and the function result is infinite. The FE_INEXACT and FE_UNDERFLOW exceptions will be raised if the function value is subnormal, and x is not equal to y. */ Tyx nextNum(Tyx, Tyy)(Tyx x, Tyy y) { static if (is(Tyx == float)) return nextafterf(x, y); else static if (is(Tyx == double)) return nextafter(x, y); else static if (is(Tyx == real)) { const real lastbit_wrt_half = 5.42101086242752217e-20L; int exponent; real mantissa = frexp(x, exponent); if (y > x) return ldexp(mantissa + lastbit_wrt_half, exponent); else return ldexp(mantissa - lastbit_wrt_half, exponent); } else static assert(0, "nextNum(): x must be float, double or real."); } unittest { // Tests of nextNum() float f = 0.5; double d = 0.5; real r = 0.5; float largef = 1000.0; double larged = 1000.0; real larger = 1000.0; float smallf = 0.1; double smalld = 0.1; real smallr = 0.1; f = nextNum(f, larger); assert(format("%.20e", f) == "5.00000059604644775390e-01"); f = nextNum(f, larger); assert(format("%.20e", f) == "5.00000119209289550780e-01"); f = 0.5; f = nextNum(f, smallf); assert(format("%.20e", f) == "4.99999970197677612300e-01"); d = nextNum(d, larged); assert(format("%.20e", d) == "5.00000000000000111020e-01"); d = nextNum(d, larged); assert(format("%.20e", d) == "5.00000000000000222040e-01"); d = 0.5; d = nextNum(d, smalld); assert(format("%.20e", d) == "4.99999999999999944480e-01"); r = nextNum(r, larger); assert(format("%.19e", r) == "5.0000000000000000004e-01"); r = nextNum(r, larger); assert(format("%.19e", r) == "5.0000000000000000008e-01"); r = 0.5; r = nextNum(r, smallr); assert(format("%.19e", r) == "4.9999999999999999995e-01"); assert(format("%.19e", nextNum(-3.0, -5.0)) == "-3.0000000000000004440e+00"); assert(format("%.19e", nextNum(-3.0, 5.0)) == "-2.9999999999999995559e+00"); } // End tests of nextNum() The starting point was: http://mail.python.org/pipermail/python-list/2001-August/099152.html Bye, bearophile |
Copyright © 1999-2021 by the D Language Foundation