www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - 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
Nov 22 2007