nextafter
bearophile
bearophileHUGS at lycos.com
Thu Nov 22 15:51:04 PST 2007
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
More information about the Digitalmars-d
mailing list