libphobos: Merge upstream phobos 38873fe6e.
authorIain Buclaw <ibuclaw@gdcproject.org>
Thu, 26 Nov 2020 10:15:32 +0000 (11:15 +0100)
committerIain Buclaw <ibuclaw@gdcproject.org>
Fri, 27 Nov 2020 20:27:13 +0000 (21:27 +0100)
Adds support for FreeBSD/x86 53-bit precision reals, and removes all
support code and tests for the extern(Pascal) calling convention.

Reviewed-on: https://github.com/dlang/phobos/pull/7704
     https://github.com/dlang/phobos/pull/7705

libphobos/ChangeLog:

* src/MERGE: Merge upstream phobos 38873fe6e.

libphobos/src/MERGE
libphobos/src/std/complex.d
libphobos/src/std/conv.d
libphobos/src/std/internal/math/gammafunction.d
libphobos/src/std/math.d
libphobos/src/std/traits.d

index de86ff5b65b5b792a97f7ecb175aebd2992826c6..cd620c9c3628f9771dbc865772d67ab3621e2a78 100644 (file)
@@ -1,4 +1,4 @@
-7948e096735adbc093333da789fc28feadce24b0
+38873fe6ee70fe8e2b7a41b7c3663e090e27d61b
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/phobos repository.
index b0780512ed32d1dcd6c719e0dba0fd2d6976b108..8e488db4162b39677abd5e8e53d20746c1f1ad4a 100644 (file)
@@ -832,8 +832,13 @@ Complex!T sin(T)(Complex!T z)  @safe pure nothrow @nogc
 @safe pure nothrow unittest
 {
     static import std.math;
+    import std.math : feqrel;
     assert(sin(complex(0.0)) == 0.0);
-    assert(sin(complex(2.0L, 0)) == std.math.sin(2.0L));
+    assert(sin(complex(2.0, 0)) == std.math.sin(2.0));
+    auto c1 = sin(complex(2.0L, 0));
+    auto c2 = complex(std.math.sin(2.0L), 0);
+    assert(feqrel(c1.re, c2.re) >= real.mant_dig - 1 &&
+        feqrel(c1.im, c2.im) >= real.mant_dig - 1);
 }
 
 
@@ -849,17 +854,20 @@ Complex!T cos(T)(Complex!T z)  @safe pure nothrow @nogc
 ///
 @safe pure nothrow unittest
 {
-    import std.complex;
-    import std.math;
+    static import std.math;
+    import std.math : feqrel;
     assert(cos(complex(0.0)) == 1.0);
-    assert(cos(complex(1.3L)) == std.math.cos(1.3L));
+    assert(cos(complex(1.3)) == std.math.cos(1.3));
     auto c1 = cos(complex(0, 5.2L));
-    auto c2 = cosh(5.2L);
+    auto c2 = complex(std.math.cosh(5.2L), 0.0L);
     assert(feqrel(c1.re, c2.re) >= real.mant_dig - 1 &&
         feqrel(c1.im, c2.im) >= real.mant_dig - 1);
+    auto c3 = cos(complex(1.3L));
+    auto c4 = complex(std.math.cos(1.3L), 0.0L);
+    assert(feqrel(c3.re, c4.re) >= real.mant_dig - 1 &&
+        feqrel(c3.im, c4.im) >= real.mant_dig - 1);
 }
 
-
 /**
     Params: y = A real number.
     Returns: The value of cos(y) + i sin(y).
index eaee62f241303da99944103542fa46e50e55c325..743d203b2bbe494995d55aa522c89dc5a7beb1be 100644 (file)
@@ -1629,6 +1629,8 @@ private void testIntegralToFloating(Integral, Floating)()
 
 private void testFloatingToIntegral(Floating, Integral)()
 {
+    import std.math : floatTraits, RealFormat;
+
     bool convFails(Source, Target, E)(Source src)
     {
         try
@@ -1660,18 +1662,23 @@ private void testFloatingToIntegral(Floating, Integral)()
     {
         a = -a; // -Integral.min not representable as an Integral
         assert(convFails!(Floating, Integral, ConvOverflowException)(a)
-                || Floating.sizeof <= Integral.sizeof);
+                || Floating.sizeof <= Integral.sizeof
+                || floatTraits!Floating.realFormat == RealFormat.ieeeExtended53);
     }
     a = 0.0 + Integral.min;
     assert(to!Integral(a) == Integral.min);
     --a; // no more representable as an Integral
     assert(convFails!(Floating, Integral, ConvOverflowException)(a)
-            || Floating.sizeof <= Integral.sizeof);
+            || Floating.sizeof <= Integral.sizeof
+            || floatTraits!Floating.realFormat == RealFormat.ieeeExtended53);
     a = 0.0 + Integral.max;
-    assert(to!Integral(a) == Integral.max || Floating.sizeof <= Integral.sizeof);
+    assert(to!Integral(a) == Integral.max
+            || Floating.sizeof <= Integral.sizeof
+            || floatTraits!Floating.realFormat == RealFormat.ieeeExtended53);
     ++a; // no more representable as an Integral
     assert(convFails!(Floating, Integral, ConvOverflowException)(a)
-            || Floating.sizeof <= Integral.sizeof);
+            || Floating.sizeof <= Integral.sizeof
+            || floatTraits!Floating.realFormat == RealFormat.ieeeExtended53);
     // convert a value with a fractional part
     a = 3.14;
     assert(to!Integral(a) == 3);
@@ -3016,7 +3023,9 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum
 @system unittest
 {
     // @system because strtod is not @safe.
-    static if (real.mant_dig == 53)
+    import std.math : floatTraits, RealFormat;
+
+    static if (floatTraits!real.realFormat == RealFormat.ieeeDouble)
     {
         import core.stdc.stdlib, std.exception, std.math;
 
@@ -3099,7 +3108,8 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum
         {
             ushort[8] value;
         }
-        else static if (floatTraits!real.realFormat == RealFormat.ieeeExtended)
+        else static if (floatTraits!real.realFormat == RealFormat.ieeeExtended ||
+                        floatTraits!real.realFormat == RealFormat.ieeeExtended53)
         {
             ushort[5] value;
         }
@@ -3122,6 +3132,8 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum
         enum s = "0x1.FFFFFFFFFFFFFFFEp-16382";
     else static if (floatTraits!real.realFormat == RealFormat.ieeeExtended)
         enum s = "0x1.FFFFFFFFFFFFFFFEp-16382";
+    else static if (floatTraits!real.realFormat == RealFormat.ieeeExtended53)
+        enum s = "0x1.FFFFFFFFFFFFFFFEp-16382";
     else static if (floatTraits!real.realFormat == RealFormat.ieeeDouble)
         enum s = "0x1.FFFFFFFFFFFFFFFEp-1000";
     else
@@ -3141,6 +3153,8 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum
         else
             ld1 = strtold(s.ptr, null);
     }
+    else static if (floatTraits!real.realFormat == RealFormat.ieeeExtended53)
+        ld1 = 0x1.FFFFFFFFFFFFFFFEp-16382L; // strtold rounds to 53 bits.
     else
         ld1 = strtold(s.ptr, null);
 
index dd206911b855a071087c810f727166520b487598..c9677c724633df4036bd8bcfb655dad5cd2b162f 100644 (file)
@@ -253,6 +253,8 @@ static if (floatTraits!(real).realFormat == RealFormat.ieeeQuadruple)
     enum real MAXGAMMA = 1755.5483429L;
 else static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended)
     enum real MAXGAMMA = 1755.5483429L;
+else static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended53)
+    enum real MAXGAMMA = 1755.5483429L;
 else static if (floatTraits!(real).realFormat == RealFormat.ieeeDouble)
     enum real MAXGAMMA = 171.6243769L;
 else
@@ -603,6 +605,11 @@ else static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended)
     enum real MAXLOG = 0x1.62e42fefa39ef358p+13L;  // log(real.max)
     enum real MINLOG = -0x1.6436716d5406e6d8p+13L; // log(real.min_normal*real.epsilon) = log(smallest denormal)
 }
+else static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended53)
+{
+    enum real MAXLOG = 0x1.62e42fefa39ef358p+13L;  // log(real.max)
+    enum real MINLOG = -0x1.6436716d5406e6d8p+13L; // log(real.min_normal*real.epsilon) = log(smallest denormal)
+}
 else static if (floatTraits!(real).realFormat == RealFormat.ieeeDouble)
 {
     enum real MAXLOG = 0x1.62e42fefa39efp+9L;  // log(real.max)
index 5cc3a858e9df17a429626ce6aebf56da8b58ffd4..3d18cfa528b923603b21ed06bcce4fb7832d0f8a 100644 (file)
@@ -495,7 +495,8 @@ T floorImpl(T)(const T x) @trusted pure nothrow @nogc
         else
             int pos = 3;
     }
-    else static if (F.realFormat == RealFormat.ieeeExtended)
+    else static if (F.realFormat == RealFormat.ieeeExtended ||
+                    F.realFormat == RealFormat.ieeeExtended53)
     {
         int exp = (y.vu[F.EXPPOS_SHORT] & 0x7fff) - 0x3fff;
 
@@ -542,7 +543,10 @@ T floorImpl(T)(const T x) @trusted pure nothrow @nogc
     }
     else
     {
-        exp = (T.mant_dig - 1) - exp;
+        static if (F.realFormat == RealFormat.ieeeExtended53)
+            exp = (T.mant_dig + 11 - 1) - exp; // mant_dig is really 64
+        else
+            exp = (T.mant_dig - 1) - exp;
 
         // Zero 16 bits at a time.
         while (exp >= 16)
@@ -1079,13 +1083,13 @@ Lret: {}
         real t = tan(x);
 
         //printf("tan(%Lg) = %Lg, should be %Lg\n", x, t, r);
-        if (!isIdentical(r, t)) assert(fabs(r-t) <= .0000001);
+        assert(approxEqual(r, t));
 
         x = -x;
         r = -r;
         t = tan(x);
         //printf("tan(%Lg) = %Lg, should be %Lg\n", x, t, r);
-        if (!isIdentical(r, t) && !(r != r && t != t)) assert(fabs(r-t) <= .0000001);
+        assert(approxEqual(r, t));
     }
     // overflow
     assert(isNaN(tan(real.infinity)));
@@ -1150,7 +1154,7 @@ float asin(float x) @safe pure nothrow @nogc  { return asin(cast(real) x); }
 
 @system unittest
 {
-    assert(equalsDigit(asin(0.5), PI / 6, useDigits));
+    assert(asin(0.5).approxEqual(PI / 6));
 }
 
 /***************
@@ -1379,7 +1383,7 @@ float atan2(float y, float x) @safe pure nothrow @nogc
 
 @system unittest
 {
-    assert(equalsDigit(atan2(1.0L, std.math.sqrt(3.0L)), PI / 6, useDigits));
+    assert(atan2(1.0, sqrt(3.0)).approxEqual(PI / 6));
 }
 
 /***********************************
@@ -1441,7 +1445,7 @@ float sinh(float x) @safe pure nothrow @nogc  { return sinh(cast(real) x); }
 
 @system unittest
 {
-    assert(equalsDigit(sinh(1.0), (E - 1.0 / E) / 2, useDigits));
+    assert(sinh(1.0).approxEqual((E - 1.0 / E) / 2));
 }
 
 /***********************************
@@ -1791,7 +1795,8 @@ real exp(real x) @trusted pure nothrow @nogc
             enum real OF =  7.09782712893383996732E2;  // ln((1-2^-53) * 2^1024)
             enum real UF = -7.451332191019412076235E2; // ln(2^-1075)
         }
-        else static if (F.realFormat == RealFormat.ieeeExtended)
+        else static if (F.realFormat == RealFormat.ieeeExtended ||
+                        F.realFormat == RealFormat.ieeeExtended53)
         {
             // Coefficients for exp(x)
             static immutable real[3] P = [
@@ -1882,7 +1887,7 @@ float exp(float x)  @safe pure nothrow @nogc   { return exp(cast(real) x); }
 
 @system unittest
 {
-    assert(equalsDigit(exp(3.0L), E * E * E, useDigits));
+    assert(exp(3.0).feqrel(E * E * E) > 16);
 }
 
 /**
@@ -2468,7 +2473,8 @@ private real exp2Impl(real x) @nogc @trusted pure nothrow
         ctrl.rounding = FloatingPointControl.roundToNearest;
     }
 
-    static if (real.mant_dig == 113)
+    enum realFormat = floatTraits!real.realFormat;
+    static if (realFormat == RealFormat.ieeeQuadruple)
     {
         static immutable real[2][] exptestpoints =
         [ //  x               exp(x)
@@ -2487,7 +2493,8 @@ private real exp2Impl(real x) @nogc @trusted pure nothrow
             [-0x1p+30L,       0                                        ], // far underflow
         ];
     }
-    else static if (real.mant_dig == 64) // 80-bit reals
+    else static if (realFormat == RealFormat.ieeeExtended ||
+                    realFormat == RealFormat.ieeeExtended53)
     {
         static immutable real[2][] exptestpoints =
         [ //  x               exp(x)
@@ -2506,7 +2513,7 @@ private real exp2Impl(real x) @nogc @trusted pure nothrow
             [-0x1p+30L,       0                            ], // far underflow
         ];
     }
-    else static if (real.mant_dig == 53) // 64-bit reals
+    else static if (realFormat == RealFormat.ieeeDouble)
     {
         static immutable real[2][] exptestpoints =
         [ //  x,             exp(x)
@@ -2527,14 +2534,14 @@ private real exp2Impl(real x) @nogc @trusted pure nothrow
     else
         static assert(0, "No exp() tests for real type!");
 
-    const minEqualDecimalDigits = real.dig - 3;
+    const minEqualMantissaBits = real.mant_dig - 13;
     real x;
     version (IeeeFlagsSupport) IeeeFlags f;
     foreach (ref pair; exptestpoints)
     {
         version (IeeeFlagsSupport) resetIeeeFlags();
         x = exp(pair[0]);
-        assert(equalsDigit(x, pair[1], minEqualDecimalDigits));
+        assert(feqrel(x, pair[1]) >= minEqualMantissaBits);
     }
 
     // Ideally, exp(0) would not set the inexact flag.
@@ -2650,7 +2657,8 @@ if (isFloatingPoint!T)
     alias F = floatTraits!T;
 
     ex = vu[F.EXPPOS_SHORT] & F.EXPMASK;
-    static if (F.realFormat == RealFormat.ieeeExtended)
+    static if (F.realFormat == RealFormat.ieeeExtended ||
+               F.realFormat == RealFormat.ieeeExtended53)
     {
         if (ex)
         {   // If exponent is non-zero
@@ -2938,7 +2946,8 @@ if (isFloatingPoint!T)
     y.rv = x;
 
     int ex = y.vu[F.EXPPOS_SHORT] & F.EXPMASK;
-    static if (F.realFormat == RealFormat.ieeeExtended)
+    static if (F.realFormat == RealFormat.ieeeExtended ||
+               F.realFormat == RealFormat.ieeeExtended53)
     {
         if (ex)
         {
@@ -3184,6 +3193,7 @@ float ldexp(float n, int exp) @safe pure nothrow @nogc { return ldexp(cast(real)
 @safe pure nothrow @nogc unittest
 {
     static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended ||
+               floatTraits!(real).realFormat == RealFormat.ieeeExtended53 ||
                floatTraits!(real).realFormat == RealFormat.ieeeQuadruple)
     {
         assert(ldexp(1.0L, -16384) == 0x1p-16384L);
@@ -4428,12 +4438,16 @@ long lrint(real x) @trusted pure nothrow @nogc
 
             return sign ? -result : result;
         }
-        else static if (F.realFormat == RealFormat.ieeeExtended)
+        else static if (F.realFormat == RealFormat.ieeeExtended ||
+                        F.realFormat == RealFormat.ieeeExtended53)
         {
             long result;
 
             // Rounding limit when casting from real(80-bit) to ulong.
-            enum real OF = 9.22337203685477580800E18L;
+            static if (F.realFormat == RealFormat.ieeeExtended)
+                enum real OF = 9.22337203685477580800E18L;
+            else
+                enum real OF = 4.50359962737049600000E15L;
 
             ushort* vu = cast(ushort*)(&x);
             uint* vi = cast(uint*)(&x);
@@ -5904,7 +5918,8 @@ bool isSubnormal(X)(X x) @trusted pure nothrow @nogc
         return (e == 0 &&
           ((ps[MANTISSA_LSB]|(ps[MANTISSA_MSB]& 0x0000_FFFF_FFFF_FFFF)) != 0));
     }
-    else static if (F.realFormat == RealFormat.ieeeExtended)
+    else static if (F.realFormat == RealFormat.ieeeExtended ||
+                    F.realFormat == RealFormat.ieeeExtended53)
     {
         ushort* pe = cast(ushort *)&x;
         long*   ps = cast(long *)&x;
@@ -5954,7 +5969,8 @@ if (isFloatingPoint!(X))
         return ((*cast(ulong *)&x) & 0x7FFF_FFFF_FFFF_FFFF)
             == 0x7FF0_0000_0000_0000;
     }
-    else static if (F.realFormat == RealFormat.ieeeExtended)
+    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;
@@ -6217,7 +6233,8 @@ F sgn(F)(F x) @safe pure nothrow @nogc
 real NaN(ulong payload) @trusted pure nothrow @nogc
 {
     alias F = floatTraits!(real);
-    static if (F.realFormat == RealFormat.ieeeExtended)
+    static if (F.realFormat == RealFormat.ieeeExtended ||
+               F.realFormat == RealFormat.ieeeExtended53)
     {
         // real80 (in x86 real format, the implied bit is actually
         // not implied but a real bit which is stored in the real)
@@ -6423,11 +6440,14 @@ real nextUp(real x) @trusted pure nothrow @nogc
         }
         return x;
     }
-    else static if (F.realFormat == RealFormat.ieeeExtended)
+    else static if (F.realFormat == RealFormat.ieeeExtended ||
+                    F.realFormat == RealFormat.ieeeExtended53)
     {
         // For 80-bit reals, the "implied bit" is a nuisance...
         ushort *pe = cast(ushort *)&x;
         ulong  *ps = cast(ulong  *)&x;
+        // EPSILON is 1 for 64-bit, and 2048 for 53-bit precision reals.
+        enum ulong EPSILON = 2UL ^^ (64 - real.mant_dig);
 
         if ((pe[F.EXPPOS_SHORT] & F.EXPMASK) == F.EXPMASK)
         {
@@ -6438,7 +6458,7 @@ real nextUp(real x) @trusted pure nothrow @nogc
         if (pe[F.EXPPOS_SHORT] & 0x8000)
         {
             // Negative number -- need to decrease the significand
-            --*ps;
+            *ps -= EPSILON;
             // Need to mask with 0x7FFF... so subnormals are treated correctly.
             if ((*ps & 0x7FFF_FFFF_FFFF_FFFF) == 0x7FFF_FFFF_FFFF_FFFF)
             {
@@ -6463,7 +6483,7 @@ real nextUp(real x) @trusted pure nothrow @nogc
         {
             // Positive number -- need to increase the significand.
             // Works automatically for positive zero.
-            ++*ps;
+            *ps += EPSILON;
             if ((*ps & 0x7FFF_FFFF_FFFF_FFFF) == 0)
             {
                 // change in exponent
@@ -7228,6 +7248,7 @@ if (isFloatingPoint!(X))
         static assert(F.realFormat == RealFormat.ieeeSingle
                     || F.realFormat == RealFormat.ieeeDouble
                     || F.realFormat == RealFormat.ieeeExtended
+                    || F.realFormat == RealFormat.ieeeExtended53
                     || F.realFormat == RealFormat.ieeeQuadruple);
 
         if (x == y)
@@ -7367,7 +7388,8 @@ body
 
     alias F = floatTraits!(T);
     T u;
-    static if (F.realFormat == RealFormat.ieeeExtended)
+    static if (F.realFormat == RealFormat.ieeeExtended ||
+               F.realFormat == RealFormat.ieeeExtended53)
     {
         // There's slight additional complexity because they are actually
         // 79-bit reals...
index 4359dfb14890adcd160b198cf7200e46e1e8a2ef..7badab4280b7b30e1e01d6e6ad757a4c742f73cf 100644 (file)
@@ -1927,7 +1927,7 @@ Determine the linkage attribute of the function.
 Params:
     func = the function symbol, or the type of a function, delegate, or pointer to function
 Returns:
-    one of the strings "D", "C", "Windows", "Pascal", or "Objective-C"
+    one of the strings "D", "C", "Windows", or "Objective-C"
 */
 template functionLinkage(func...)
     if (func.length == 1 && isCallable!func)
@@ -2148,7 +2148,7 @@ template SetFunctionAttributes(T, string linkage, uint attrs)
             !(attrs & FunctionAttribute.safe),
             "Cannot have a function/delegate that is both trusted and safe.");
 
-        static immutable linkages = ["D", "C", "Windows", "Pascal", "C++", "System"];
+        static immutable linkages = ["D", "C", "Windows", "C++", "System"];
         static assert(canFind(linkages, linkage), "Invalid linkage '" ~
             linkage ~ "', must be one of " ~ linkages.stringof ~ ".");
 
@@ -2263,7 +2263,7 @@ version (unittest)
             // Check that all linkage types work (D-style variadics require D linkage).
             static if (variadicFunctionStyle!T != Variadic.d)
             {
-                foreach (newLinkage; AliasSeq!("D", "C", "Windows", "Pascal", "C++"))
+                foreach (newLinkage; AliasSeq!("D", "C", "Windows", "C++"))
                 {
                     alias New = SetFunctionAttributes!(T, newLinkage, attrs);
                     static assert(functionLinkage!New == newLinkage,