View mode: basic / threaded / horizontal-split · Log in · Help
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
Top | Discussion index | About this forum | D home