Wolfgang Thallergcc 15.1.0ada185d1 year agoHistory
1062 lines · 29.4 KB · D
RawDownload
// Written in the D programming language. /**This is a submodule of $(MREF std, math). It contains several functions for introspection on numerical values. Copyright: Copyright The D Language Foundation 2000 - 2011.License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).Authors:   $(HTTP digitalmars.com, Walter Bright), Don Clugston,           Conversion of CEPHES math library to D by Iain Buclaw and David NadlingerSource: $(PHOBOSSRC std/math/traits.d) Macros:    NAN = $(RED NAN)    PLUSMN = &plusmn;    INFIN = &infin; */ module std.math.traits; import std.traits : isFloatingPoint, isIntegral, isNumeric, isSigned;  /********************************* * Determines if $(D_PARAM x) is NaN. * Params: *  x = a floating point number. * Returns: *  `true` if $(D_PARAM x) is Nan. */bool isNaN(X)(X x) @nogc @trusted pure nothrowif (isFloatingPoint!(X)){    version (all)    {        return x != x;    }    else    {        /*        Code kept for historical context. At least on Intel, the simple test        x != x uses one dedicated instruction (ucomiss/ucomisd) that runs in one        cycle. Code for 80- and 128-bits is larger but still smaller than the        integrals-based solutions below. Future revisions may enable the code        below conditionally depending on hardware.        */        alias F = floatTraits!(X);        static if (F.realFormat == RealFormat.ieeeSingle)        {            const uint p = *cast(uint *)&x;            // Sign bit (MSB) is irrelevant so mask it out.            // Next 8 bits should be all set.            // At least one bit among the least significant 23 bits should be set.            return (p & 0x7FFF_FFFF) > 0x7F80_0000;        }        else static if (F.realFormat == RealFormat.ieeeDouble)        {            const ulong  p = *cast(ulong *)&x;            // Sign bit (MSB) is irrelevant so mask it out.            // Next 11 bits should be all set.            // At least one bit among the least significant 52 bits should be set.            return (p & 0x7FFF_FFFF_FFFF_FFFF) > 0x7FF0_0000_0000_0000;        }        else static if (F.realFormat == RealFormat.ieeeExtended ||                        F.realFormat == RealFormat.ieeeExtended53)        {            const ushort e = F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT];            const ulong ps = *cast(ulong *)&x;            return e == F.EXPMASK &&                ps & 0x7FFF_FFFF_FFFF_FFFF; // not infinity        }        else static if (F.realFormat == RealFormat.ieeeQuadruple)        {            const ushort e = F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT];            const ulong psLsb = (cast(ulong *)&x)[MANTISSA_LSB];            const ulong psMsb = (cast(ulong *)&x)[MANTISSA_MSB];            return e == F.EXPMASK &&                (psLsb | (psMsb& 0x0000_FFFF_FFFF_FFFF)) != 0;        }        else        {            return x != x;        }    }} ///@safe pure nothrow @nogc unittest{    assert( isNaN(float.init));    assert( isNaN(-double.init));    assert( isNaN(real.nan));    assert( isNaN(-real.nan));    assert(!isNaN(cast(float) 53.6));    assert(!isNaN(cast(real)-53.6));} @safe pure nothrow @nogc unittest{    import std.meta : AliasSeq;     static foreach (T; AliasSeq!(float, double, real))    {{        // CTFE-able tests        assert(isNaN(T.init));        assert(isNaN(-T.init));        assert(isNaN(T.nan));        assert(isNaN(-T.nan));        assert(!isNaN(T.infinity));        assert(!isNaN(-T.infinity));        assert(!isNaN(cast(T) 53.6));        assert(!isNaN(cast(T)-53.6));         // Runtime tests        shared T f;        f = T.init;        assert(isNaN(f));        assert(isNaN(-f));        f = T.nan;        assert(isNaN(f));        assert(isNaN(-f));        f = T.infinity;        assert(!isNaN(f));        assert(!isNaN(-f));        f = cast(T) 53.6;        assert(!isNaN(f));        assert(!isNaN(-f));    }}} /********************************* * Determines if $(D_PARAM x) is finite. * Params: *  x = a floating point number. * Returns: *  `true` if $(D_PARAM x) is finite. */bool isFinite(X)(X x) @trusted pure nothrow @nogc{    import std.math.traits : floatTraits, RealFormat;     static if (__traits(isFloating, X))        if (__ctfe)            return x == x && x != X.infinity && x != -X.infinity;    alias F = floatTraits!(X);    ushort* pe = cast(ushort *)&x;    return (pe[F.EXPPOS_SHORT] & F.EXPMASK) != F.EXPMASK;} ///@safe pure nothrow @nogc unittest{    assert( isFinite(1.23f));    assert( isFinite(float.max));    assert( isFinite(float.min_normal));    assert(!isFinite(float.nan));    assert(!isFinite(float.infinity));} @safe pure nothrow @nogc unittest{    assert(isFinite(1.23));    assert(isFinite(double.max));    assert(isFinite(double.min_normal));    assert(!isFinite(double.nan));    assert(!isFinite(double.infinity));     assert(isFinite(1.23L));    assert(isFinite(real.max));    assert(isFinite(real.min_normal));    assert(!isFinite(real.nan));    assert(!isFinite(real.infinity));     //CTFE    static assert(isFinite(1.23));    static assert(isFinite(double.max));    static assert(isFinite(double.min_normal));    static assert(!isFinite(double.nan));    static assert(!isFinite(double.infinity));     static assert(isFinite(1.23L));    static assert(isFinite(real.max));    static assert(isFinite(real.min_normal));    static assert(!isFinite(real.nan));    static assert(!isFinite(real.infinity));}  /********************************* * Determines if $(D_PARAM x) is normalized. * * A normalized number must not be zero, subnormal, infinite nor $(NAN). * * Params: *  x = a floating point number. * Returns: *  `true` if $(D_PARAM x) is normalized. */ /* Need one for each format because subnormal floats might * be converted to normal reals. */bool isNormal(X)(X x) @trusted pure nothrow @nogc{    import std.math.traits : floatTraits, RealFormat;     static if (__traits(isFloating, X))        if (__ctfe)            return (x <= -X.min_normal && x != -X.infinity) || (x >= X.min_normal && x != X.infinity);    alias F = floatTraits!(X);    ushort e = F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT];    return (e != F.EXPMASK && e != 0);} ///@safe pure nothrow @nogc unittest{    float f = 3;    double d = 500;    real e = 10e+48;     assert(isNormal(f));    assert(isNormal(d));    assert(isNormal(e));    f = d = e = 0;    assert(!isNormal(f));    assert(!isNormal(d));    assert(!isNormal(e));    assert(!isNormal(real.infinity));    assert(isNormal(-real.max));    assert(!isNormal(real.min_normal/4)); } @safe pure nothrow @nogc unittest{    // CTFE    enum float f = 3;    enum double d = 500;    enum real e = 10e+48;     static assert(isNormal(f));    static assert(isNormal(d));    static assert(isNormal(e));     static assert(!isNormal(0.0f));    static assert(!isNormal(0.0));    static assert(!isNormal(0.0L));    static assert(!isNormal(real.infinity));    static assert(isNormal(-real.max));    static assert(!isNormal(real.min_normal/4));} /********************************* * Determines if $(D_PARAM x) is subnormal. * * Subnormals (also known as "denormal number"), have a 0 exponent * and a 0 most significant mantissa bit. * * Params: *  x = a floating point number. * Returns: *  `true` if $(D_PARAM x) is a denormal number. */bool isSubnormal(X)(X x) @trusted pure nothrow @nogc{    import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;     static if (__traits(isFloating, X))        if (__ctfe)            return -X.min_normal < x && x < X.min_normal;    /*        Need one for each format because subnormal floats might        be converted to normal reals.    */    alias F = floatTraits!(X);    static if (F.realFormat == RealFormat.ieeeSingle)    {        uint *p = cast(uint *)&x;        return (*p & F.EXPMASK_INT) == 0 && *p & F.MANTISSAMASK_INT;    }    else static if (F.realFormat == RealFormat.ieeeDouble)    {        uint *p = cast(uint *)&x;        return (p[MANTISSA_MSB] & F.EXPMASK_INT) == 0            && (p[MANTISSA_LSB] || p[MANTISSA_MSB] & F.MANTISSAMASK_INT);    }    else static if (F.realFormat == RealFormat.ieeeQuadruple)    {        ushort e = F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT];        long*   ps = cast(long *)&x;        return (e == 0 &&          ((ps[MANTISSA_LSB]|(ps[MANTISSA_MSB]& 0x0000_FFFF_FFFF_FFFF)) != 0));    }    else static if (F.realFormat == RealFormat.ieeeExtended ||                    F.realFormat == RealFormat.ieeeExtended53)    {        ushort* pe = cast(ushort *)&x;        long*   ps = cast(long *)&x;         return (pe[F.EXPPOS_SHORT] & F.EXPMASK) == 0 && *ps > 0;    }    else    {        static assert(false, "Not implemented for this architecture");    }} ///@safe pure nothrow @nogc unittest{    import std.meta : AliasSeq;     static foreach (T; AliasSeq!(float, double, real))    {{        T f;        for (f = 1.0; !isSubnormal(f); f /= 2)            assert(f != 0);    }}} @safe pure nothrow @nogc unittest{    static bool subnormalTest(T)()    {        T f;        for (f = 1.0; !isSubnormal(f); f /= 2)            if (f == 0)                return false;        return true;    }    static assert(subnormalTest!float());    static assert(subnormalTest!double());    static assert(subnormalTest!real());} /********************************* * Determines if $(D_PARAM x) is $(PLUSMN)$(INFIN). * Params: *  x = a floating point number. * Returns: *  `true` if $(D_PARAM x) is $(PLUSMN)$(INFIN). */bool isInfinity(X)(X x) @nogc @trusted pure nothrowif (isFloatingPoint!(X)){    import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;     alias F = floatTraits!(X);    static if (F.realFormat == RealFormat.ieeeSingle)    {        return ((*cast(uint *)&x) & 0x7FFF_FFFF) == 0x7F80_0000;    }    else static if (F.realFormat == RealFormat.ieeeDouble)    {        return ((*cast(ulong *)&x) & 0x7FFF_FFFF_FFFF_FFFF)            == 0x7FF0_0000_0000_0000;    }    else static if (F.realFormat == RealFormat.ieeeExtended ||                    F.realFormat == RealFormat.ieeeExtended53)    {        const ushort e = cast(ushort)(F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT]);        const ulong ps = *cast(ulong *)&x;         // On Motorola 68K, infinity can have hidden bit = 1 or 0. On x86, it is always 1.        return e == F.EXPMASK && (ps & 0x7FFF_FFFF_FFFF_FFFF) == 0;    }    else static if (F.realFormat == RealFormat.ieeeQuadruple)    {        const long psLsb = (cast(long *)&x)[MANTISSA_LSB];        const long psMsb = (cast(long *)&x)[MANTISSA_MSB];        return (psLsb == 0)            && (psMsb & 0x7FFF_FFFF_FFFF_FFFF) == 0x7FFF_0000_0000_0000;    }    else    {        return (x < -X.max) || (X.max < x);    }} ///@nogc @safe pure nothrow unittest{    assert(!isInfinity(float.init));    assert(!isInfinity(-float.init));    assert(!isInfinity(float.nan));    assert(!isInfinity(-float.nan));    assert(isInfinity(float.infinity));    assert(isInfinity(-float.infinity));    assert(isInfinity(-1.0f / 0.0f));} @safe pure nothrow @nogc unittest{    // CTFE-able tests    assert(!isInfinity(double.init));    assert(!isInfinity(-double.init));    assert(!isInfinity(double.nan));    assert(!isInfinity(-double.nan));    assert(isInfinity(double.infinity));    assert(isInfinity(-double.infinity));    assert(isInfinity(-1.0 / 0.0));     assert(!isInfinity(real.init));    assert(!isInfinity(-real.init));    assert(!isInfinity(real.nan));    assert(!isInfinity(-real.nan));    assert(isInfinity(real.infinity));    assert(isInfinity(-real.infinity));    assert(isInfinity(-1.0L / 0.0L));     // Runtime tests    shared float f;    f = float.init;    assert(!isInfinity(f));    assert(!isInfinity(-f));    f = float.nan;    assert(!isInfinity(f));    assert(!isInfinity(-f));    f = float.infinity;    assert(isInfinity(f));    assert(isInfinity(-f));    f = (-1.0f / 0.0f);    assert(isInfinity(f));     shared double d;    d = double.init;    assert(!isInfinity(d));    assert(!isInfinity(-d));    d = double.nan;    assert(!isInfinity(d));    assert(!isInfinity(-d));    d = double.infinity;    assert(isInfinity(d));    assert(isInfinity(-d));    d = (-1.0 / 0.0);    assert(isInfinity(d));     shared real e;    e = real.init;    assert(!isInfinity(e));    assert(!isInfinity(-e));    e = real.nan;    assert(!isInfinity(e));    assert(!isInfinity(-e));    e = real.infinity;    assert(isInfinity(e));    assert(isInfinity(-e));    e = (-1.0L / 0.0L);    assert(isInfinity(e));} @nogc @safe pure nothrow unittest{    import std.meta : AliasSeq;    static bool foo(T)(inout T x) { return isInfinity(x); }    foreach (T; AliasSeq!(float, double, real))    {        assert(!foo(T(3.14f)));        assert(foo(T.infinity));    }} /********************************* * Is the binary representation of x identical to y? */bool isIdentical(real x, real y) @trusted pure nothrow @nogc{    if (__ctfe)    {        if (x !is y) return false;        if (x == x) return true; // If not NaN `is` implies identical representation.        static if (double.mant_dig != real.mant_dig)        {            // Works because we are in CTFE and there is no way in CTFE to set more            // bits of NaN payload than can fit in a double, and since 2.087            // changed real.init to be non-signaling I *think* there is no way in            // CTFE for a real to be a signaling NaN unless real and double have            // the same representation so real's bits can be manipulated directly.            double d1 = x, d2 = y;        }        else        {            // Alias to avoid converting signaling to quiet.            alias d1 = x;            alias d2 = y;        }        return *cast(long*) &d1 == *cast(long*) &d2;    }    // We're doing a bitwise comparison so the endianness is irrelevant.    long*   pxs = cast(long *)&x;    long*   pys = cast(long *)&y;    alias F = floatTraits!(real);    static if (F.realFormat == RealFormat.ieeeDouble)    {        return pxs[0] == pys[0];    }    else static if (F.realFormat == RealFormat.ieeeQuadruple)    {

Lines 1–500 of 1062.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t