Changing Math.Max, Math.Min, Math.MaxMagnitude, and Math.MinMagnitude to propagate...
authorTanner Gooding <tagoo@outlook.com>
Wed, 17 Apr 2019 03:13:12 +0000 (20:13 -0700)
committerJan Kotas <jkotas@microsoft.com>
Wed, 17 Apr 2019 03:13:12 +0000 (20:13 -0700)
src/System.Private.CoreLib/shared/System/Math.cs
src/System.Private.CoreLib/shared/System/MathF.cs

index 1c36c9d..ac9be48 100644 (file)
@@ -538,31 +538,23 @@ namespace System
 
         public static double Max(double val1, double val2)
         {
-            // When val1 and val2 are both finite or infinite, return the larger
-            //  * We count +0.0 as larger than -0.0 to match MSVC
-            // When val1 or val2, but not both, are NaN return the opposite
-            //  * We return the opposite if either is NaN to match MSVC
+            // This matches the IEEE 754:2019 `maximum` function
+            //
+            // It propagates NaN inputs back to the caller and
+            // otherwise returns the larger of the inputs. It
+            // treats +0 as larger than -0 as per the specification.
 
-            if (double.IsNaN(val1))
-            {
-                return val2;
-            }
-
-            if (double.IsNaN(val2))
+            if ((val1 > val2) || double.IsNaN(val1))
             {
                 return val1;
             }
 
-            // We do this comparison first and separately to handle the -0.0 to +0.0 comparision
-            // * Doing (val1 < val2) first could get transformed into (val2 >= val1) by the JIT
-            //   which would then return an incorrect value
-
             if (val1 == val2)
             {
                 return double.IsNegative(val1) ? val2 : val1;
             }
 
-            return (val1 < val2) ? val2 : val1;
+            return val2;
         }
 
         [NonVersionable]
@@ -592,31 +584,23 @@ namespace System
         
         public static float Max(float val1, float val2)
         {
-            // When val1 and val2 are both finite or infinite, return the larger
-            //  * We count +0.0 as larger than -0.0 to match MSVC
-            // When val1 or val2, but not both, are NaN return the opposite
-            //  * We return the opposite if either is NaN to match MSVC
+            // This matches the IEEE 754:2019 `maximum` function
+            //
+            // It propagates NaN inputs back to the caller and
+            // otherwise returns the larger of the inputs. It
+            // treats +0 as larger than -0 as per the specification.
 
-            if (float.IsNaN(val1))
-            {
-                return val2;
-            }
-
-            if (float.IsNaN(val2))
+            if ((val1 > val2) || float.IsNaN(val1))
             {
                 return val1;
             }
 
-            // We do this comparison first and separately to handle the -0.0 to +0.0 comparision
-            // * Doing (val1 < val2) first could get transformed into (val2 >= val1) by the JIT
-            //   which would then return an incorrect value
-
             if (val1 == val2)
             {
                 return float.IsNegative(val1) ? val2 : val1;
             }
 
-            return (val1 < val2) ? val2 : val1;
+            return val2;
         }
 
         [CLSCompliant(false)]
@@ -642,34 +626,26 @@ namespace System
 
         public static double MaxMagnitude(double x, double y)
         {
-            // When x and y are both finite or infinite, return the larger magnitude
-            //  * We count +0.0 as larger than -0.0 to match MSVC
-            // When x or y, but not both, are NaN return the opposite
-            //  * We return the opposite if either is NaN to match MSVC
+            // This matches the IEEE 754:2019 `maximumMagnitude` function
+            //
+            // It propagates NaN inputs back to the caller and
+            // otherwise returns the input with a larger magnitude.
+            // It treats +0 as larger than -0 as per the specification.
 
-            if (double.IsNaN(x))
-            {
-                return y;
-            }
+            double ax = Abs(x);
+            double ay = Abs(y);
 
-            if (double.IsNaN(y))
+            if ((ax > ay) || double.IsNaN(ax))
             {
                 return x;
             }
 
-            // We do this comparison first and separately to handle the -0.0 to +0.0 comparision
-            // * Doing (ax < ay) first could get transformed into (ay >= ax) by the JIT which would
-            //   then return an incorrect value
-
-            double ax = Abs(x);
-            double ay = Abs(y);
-
             if (ax == ay)
             {
                 return double.IsNegative(x) ? y : x;
             }
 
-            return (ax < ay) ? y : x;
+            return y;
         }
 
         [NonVersionable]
@@ -686,31 +662,23 @@ namespace System
 
         public static double Min(double val1, double val2)
         {
-            // When val1 and val2 are both finite or infinite, return the smaller
-            //  * We count -0.0 as smaller than -0.0 to match MSVC
-            // When val1 or val2, but not both, are NaN return the opposite
-            //  * We return the opposite if either is NaN to match MSVC
+            // This matches the IEEE 754:2019 `minimum` function
+            //
+            // It propagates NaN inputs back to the caller and
+            // otherwise returns the larger of the inputs. It
+            // treats +0 as larger than -0 as per the specification.
 
-            if (double.IsNaN(val1))
-            {
-                return val2;
-            }
-
-            if (double.IsNaN(val2))
+            if ((val1 < val2) || double.IsNaN(val1))
             {
                 return val1;
             }
 
-            // We do this comparison first and separately to handle the -0.0 to +0.0 comparision
-            // * Doing (val1 < val2) first could get transformed into (val2 >= val1) by the JIT
-            //   which would then return an incorrect value
-
             if (val1 == val2)
             {
                 return double.IsNegative(val1) ? val1 : val2;
             }
 
-            return (val1 < val2) ? val1 : val2;
+            return val2;
         }
 
         [NonVersionable]
@@ -740,31 +708,23 @@ namespace System
 
         public static float Min(float val1, float val2)
         {
-            // When val1 and val2 are both finite or infinite, return the smaller
-            //  * We count -0.0 as smaller than -0.0 to match MSVC
-            // When val1 or val2, but not both, are NaN return the opposite
-            //  * We return the opposite if either is NaN to match MSVC
+            // This matches the IEEE 754:2019 `minimum` function
+            //
+            // It propagates NaN inputs back to the caller and
+            // otherwise returns the larger of the inputs. It
+            // treats +0 as larger than -0 as per the specification.
 
-            if (float.IsNaN(val1))
-            {
-                return val2;
-            }
-
-            if (float.IsNaN(val2))
+            if ((val1 < val2) || float.IsNaN(val1))
             {
                 return val1;
             }
 
-            // We do this comparison first and separately to handle the -0.0 to +0.0 comparision
-            // * Doing (val1 < val2) first could get transformed into (val2 >= val1) by the JIT
-            //   which would then return an incorrect value
-
             if (val1 == val2)
             {
                 return float.IsNegative(val1) ? val1 : val2;
             }
 
-            return (val1 < val2) ? val1 : val2;
+            return val2;
         }
 
         [CLSCompliant(false)]
@@ -790,34 +750,26 @@ namespace System
 
         public static double MinMagnitude(double x, double y)
         {
-            // When x and y are both finite or infinite, return the smaller magnitude
-            //  * We count -0.0 as smaller than -0.0 to match MSVC
-            // When x or y, but not both, are NaN return the opposite
-            //  * We return the opposite if either is NaN to match MSVC
+            // This matches the IEEE 754:2019 `minimumMagnitude` function
+            //
+            // It propagates NaN inputs back to the caller and
+            // otherwise returns the input with a larger magnitude.
+            // It treats +0 as larger than -0 as per the specification.
 
-            if (double.IsNaN(x))
-            {
-                return y;
-            }
+            double ax = Abs(x);
+            double ay = Abs(y);
 
-            if (double.IsNaN(y))
+            if ((ax < ay) || double.IsNaN(ax))
             {
                 return x;
             }
 
-            // We do this comparison first and separately to handle the -0.0 to +0.0 comparision
-            // * Doing (ax < ay) first could get transformed into (ay >= ax) by the JIT which would
-            //   then return an incorrect value
-
-            double ax = Abs(x);
-            double ay = Abs(y);
-
             if (ax == ay)
             {
                 return double.IsNegative(x) ? x : y;
             }
 
-            return (ax < ay) ? x : y;
+            return y;
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
index 1defa4e..bf32486 100644 (file)
@@ -190,34 +190,26 @@ namespace System
 
         public static float MaxMagnitude(float x, float y)
         {
-            // When x and y are both finite or infinite, return the larger magnitude
-            //  * We count +0.0 as larger than -0.0 to match MSVC
-            // When x or y, but not both, are NaN return the opposite
-            //  * We return the opposite if either is NaN to match MSVC
+            // This matches the IEEE 754:2019 `maximumMagnitude` function
+            //
+            // It propagates NaN inputs back to the caller and
+            // otherwise returns the input with a larger magnitude.
+            // It treats +0 as larger than -0 as per the specification.
 
-            if (float.IsNaN(x))
-            {
-                return y;
-            }
+            float ax = Abs(x);
+            float ay = Abs(y);
 
-            if (float.IsNaN(y))
+            if ((ax > ay) || float.IsNaN(ax))
             {
                 return x;
             }
 
-            // We do this comparison first and separately to handle the -0.0 to +0.0 comparision
-            // * Doing (ax < ay) first could get transformed into (ay >= ax) by the JIT which would
-            //   then return an incorrect value
-
-            float ax = Abs(x);
-            float ay = Abs(y);
-
             if (ax == ay)
             {
                 return float.IsNegative(x) ? y : x;
             }
 
-            return (ax < ay) ? y : x;
+            return y;
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -228,34 +220,26 @@ namespace System
 
         public static float MinMagnitude(float x, float y)
         {
-            // When x and y are both finite or infinite, return the smaller magnitude
-            //  * We count -0.0 as smaller than -0.0 to match MSVC
-            // When x or y, but not both, are NaN return the opposite
-            //  * We return the opposite if either is NaN to match MSVC
+            // This matches the IEEE 754:2019 `minimumMagnitude` function
+            //
+            // It propagates NaN inputs back to the caller and
+            // otherwise returns the input with a larger magnitude.
+            // It treats +0 as larger than -0 as per the specification.
 
-            if (float.IsNaN(x))
-            {
-                return y;
-            }
+            float ax = Abs(x);
+            float ay = Abs(y);
 
-            if (float.IsNaN(y))
+            if ((ax < ay) || float.IsNaN(ax))
             {
                 return x;
             }
 
-            // We do this comparison first and separately to handle the -0.0 to +0.0 comparision
-            // * Doing (ax < ay) first could get transformed into (ay >= ax) by the JIT which would
-            //   then return an incorrect value
-
-            float ax = Abs(x);
-            float ay = Abs(y);
-
             if (ax == ay)
             {
                 return float.IsNegative(x) ? x : y;
             }
 
-            return (ax < ay) ? x : y;
+            return y;
         }
 
         [Intrinsic]