Fixing impMathIntrinsic to not insert unnecessary casts (#47923)
authorTanner Gooding <tagoo@outlook.com>
Tue, 9 Feb 2021 17:17:18 +0000 (09:17 -0800)
committerGitHub <noreply@github.com>
Tue, 9 Feb 2021 17:17:18 +0000 (09:17 -0800)
* Add the Math benchmarks as tests

* Fixing impMathIntrinsic to not insert unnecessary casts

65 files changed:
src/coreclr/jit/importer.cpp
src/tests/JIT/Math/Functions/Double/AbsDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/AcosDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/Acosh.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/AsinDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/Asinh.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/Atan2Double.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/AtanDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/Atanh.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/Cbrt.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/CeilingDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/CopySignDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/CosDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/CoshDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/ExpDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/FloorDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/FusedMultiplyAdd.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/ILogB.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/Log10Double.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/Log2.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/LogDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/MaxDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/MinDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/PowDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/RoundDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/ScaleB.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/SinDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/SinhDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/SqrtDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/TanDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Double/TanhDouble.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Functions_r.csproj [new file with mode: 0644]
src/tests/JIT/Math/Functions/Functions_ro.csproj [new file with mode: 0644]
src/tests/JIT/Math/Functions/MathTests.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Program.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/AbsSingle.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/AcosSingle.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/Acosh.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/AsinSingle.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/Asinh.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/Atan2Single.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/AtanSingle.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/Atanh.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/Cbrt.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/CeilingSingle.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/CopySignSingle.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/CosSingle.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/CoshSingle.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/ExpSingle.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/FloorSingle.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/FusedMultiplyAdd.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/ILogB.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/Log10Single.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/Log2.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/LogSingle.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/MaxSingle.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/MinSingle.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/PowSingle.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/RoundSingle.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/ScaleB.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/SinSingle.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/SinhSingle.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/SqrtSingle.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/TanSingle.cs [new file with mode: 0644]
src/tests/JIT/Math/Functions/Single/TanhSingle.cs [new file with mode: 0644]

index 7516c0c..acf0975 100644 (file)
@@ -4615,15 +4615,22 @@ GenTree* Compiler::impMathIntrinsic(CORINFO_METHOD_HANDLE method,
     if (!IsIntrinsicImplementedByUserCall(intrinsicName))
 #endif
     {
+        CORINFO_CLASS_HANDLE    tmpClass;
+        CORINFO_ARG_LIST_HANDLE arg;
+        var_types               op1Type;
+        var_types               op2Type;
+
         switch (sig->numArgs)
         {
             case 1:
                 op1 = impPopStack().val;
 
-                assert(varTypeIsFloating(op1));
+                arg     = sig->args;
+                op1Type = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg, &tmpClass)));
 
-                if (op1->TypeGet() != callType)
+                if (op1->TypeGet() != genActualType(op1Type))
                 {
+                    assert(varTypeIsFloating(op1));
                     op1 = gtNewCastNode(callType, op1, false, callType);
                 }
 
@@ -4635,16 +4642,22 @@ GenTree* Compiler::impMathIntrinsic(CORINFO_METHOD_HANDLE method,
                 op2 = impPopStack().val;
                 op1 = impPopStack().val;
 
-                assert(varTypeIsFloating(op1));
-                assert(varTypeIsFloating(op2));
+                arg     = sig->args;
+                op1Type = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg, &tmpClass)));
 
-                if (op2->TypeGet() != callType)
+                if (op1->TypeGet() != genActualType(op1Type))
                 {
-                    op2 = gtNewCastNode(callType, op2, false, callType);
+                    assert(varTypeIsFloating(op1));
+                    op1 = gtNewCastNode(callType, op1, false, callType);
                 }
-                if (op1->TypeGet() != callType)
+
+                arg     = info.compCompHnd->getArgNext(arg);
+                op2Type = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg, &tmpClass)));
+
+                if (op2->TypeGet() != genActualType(op2Type))
                 {
-                    op1 = gtNewCastNode(callType, op1, false, callType);
+                    assert(varTypeIsFloating(op2));
+                    op2 = gtNewCastNode(callType, op2, false, callType);
                 }
 
                 op1 = new (this, GT_INTRINSIC) GenTreeIntrinsic(genActualType(callType), op1, op2,
diff --git a/src/tests/JIT/Math/Functions/Double/AbsDouble.cs b/src/tests/JIT/Math/Functions/Double/AbsDouble.cs
new file mode 100644 (file)
index 0000000..13eeb4d
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Abs(double) over 5000 iterations for the domain -1, +1
+
+        private const double absDelta = 0.0004;
+        private const double absExpectedResult = 2499.9999999999659;
+
+        public void Abs() => AbsTest();
+
+        public static void AbsTest()
+        {
+            double result = 0.0, value = -1.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += absDelta;
+                result += Math.Abs(value);
+            }
+
+            double diff = Math.Abs(absExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {absExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/AcosDouble.cs b/src/tests/JIT/Math/Functions/Double/AcosDouble.cs
new file mode 100644 (file)
index 0000000..2dd8a3d
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Acos(double) over 5000 iterations for the domain -1, +1
+
+        private const double acosDelta = 0.0004;
+        private const double acosExpectedResult = 7852.4108380716079;
+
+        public void Acos() => AcosTest();
+
+        public static void AcosTest()
+        {
+            double result = 0.0, value = -1.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += acosDelta;
+                result += Math.Acos(value);
+            }
+
+            double diff = Math.Abs(acosExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {acosExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/Acosh.cs b/src/tests/JIT/Math/Functions/Double/Acosh.cs
new file mode 100644 (file)
index 0000000..8da1e67
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Acosh(double) over 5000 iterations for the domain +1, +3
+
+        private const double acoshDelta = 0.0004;
+        private const double acoshExpectedResult = 6148.648751739127;
+
+        public void Acosh() => AcoshTest();
+
+        public static void AcoshTest()
+        {
+            double result = 0.0, value = 1.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                result += Math.Acosh(value);
+                value += acoshDelta;
+            }
+
+            double diff = Math.Abs(acoshExpectedResult - result);
+
+            if (double.IsNaN(result) || (diff > MathTests.DoubleEpsilon))
+            {
+                throw new Exception($"Expected Result {acoshExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/AsinDouble.cs b/src/tests/JIT/Math/Functions/Double/AsinDouble.cs
new file mode 100644 (file)
index 0000000..7f9ce58
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Asin(double) over 5000 iterations for the domain -1, +1
+
+        private const double asinDelta = 0.0004;
+        private const double asinExpectedResult = 1.5707959028763392;
+
+        public void Asin() => AsinTest();
+
+        public static void AsinTest()
+        {
+            double result = 0.0, value = -1.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += asinDelta;
+                result += Math.Asin(value);
+            }
+
+            double diff = Math.Abs(asinExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {asinExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/Asinh.cs b/src/tests/JIT/Math/Functions/Double/Asinh.cs
new file mode 100644 (file)
index 0000000..e52e9f4
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Asinh(double) over 5000 iterations for the domain -1, +1
+
+        private const double asinhDelta = 0.0004;
+        private const double asinhExpectedResult = -0.88137358721605752;
+
+        public void Asinh() => AsinhTest();
+
+        public static void AsinhTest()
+        {
+            double result = 0.0, value = -1.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                result += Math.Asinh(value);
+                value += asinhDelta;
+            }
+
+            double diff = Math.Abs(asinhExpectedResult - result);
+
+            if (double.IsNaN(result) || (diff > MathTests.DoubleEpsilon))
+            {
+                throw new Exception($"Expected Result {asinhExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/Atan2Double.cs b/src/tests/JIT/Math/Functions/Double/Atan2Double.cs
new file mode 100644 (file)
index 0000000..c56fa2f
--- /dev/null
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Atan2(double, double) over 5000 iterations for the domain y: -1, +1; x: +1, -1
+
+        private const double atan2DeltaX = -0.0004;
+        private const double atan2DeltaY = 0.0004;
+        private const double atan2ExpectedResult = 3926.99081698702;
+
+        public void Atan2() => Atan2Test();
+
+        public static void Atan2Test()
+        {
+            double result = 0.0, valueX = 1.0, valueY = -1.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                valueX += atan2DeltaX; valueY += atan2DeltaY;
+                result += Math.Atan2(valueY, valueX);
+            }
+
+            double diff = Math.Abs(atan2ExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {atan2ExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/AtanDouble.cs b/src/tests/JIT/Math/Functions/Double/AtanDouble.cs
new file mode 100644 (file)
index 0000000..d1739b8
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Atan(double) over 5000 iterations for the domain -1, +1
+
+        private const double atanDelta = 0.0004;
+        private const double atanExpectedResult = 0.78539816322061329;
+
+        public void Atan() => AtanTest();
+
+        public static void AtanTest()
+        {
+            double result = 0.0, value = -1.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += atanDelta;
+                result += Math.Atan(value);
+            }
+
+            double diff = Math.Abs(atanExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {atanExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/Atanh.cs b/src/tests/JIT/Math/Functions/Double/Atanh.cs
new file mode 100644 (file)
index 0000000..d1394db
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Atanh(double) over 5000 iterations for the domain -1, +1
+
+        private const double atanhDelta = 0.0004;
+        private const double atanhExpectedResult = float.NegativeInfinity;
+
+        public void Atanh() => AtanhTest();
+
+        public static void AtanhTest()
+        {
+            double result = 0.0, value = -1.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                result += Math.Atanh(value);
+                value += atanhDelta;
+            }
+
+            double diff = Math.Abs(atanhExpectedResult - result);
+
+            if (double.IsNaN(result) || (diff > MathTests.DoubleEpsilon))
+            {
+                throw new Exception($"Expected Result {atanhExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/Cbrt.cs b/src/tests/JIT/Math/Functions/Double/Cbrt.cs
new file mode 100644 (file)
index 0000000..b6b0a91
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Cbrt(double) over 5000 iterations for the domain +0, +PI
+
+        private const double cbrtDelta = 0.0006283185307180;
+        private const double cbrtExpectedResult = 5491.4635361574383;
+
+        public void Cbrt() => CbrtTest();
+
+        public static void CbrtTest()
+        {
+            double result = 0.0, value = 0.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                result += Math.Cbrt(value);
+                value += cbrtDelta;
+            }
+
+            double diff = Math.Abs(cbrtExpectedResult - result);
+
+            if (double.IsNaN(result) || (diff > MathTests.DoubleEpsilon))
+            {
+                throw new Exception($"Expected Result {cbrtExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/CeilingDouble.cs b/src/tests/JIT/Math/Functions/Double/CeilingDouble.cs
new file mode 100644 (file)
index 0000000..c050c7c
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Ceiling(double) over 5000 iterations for the domain -1, +1
+
+        private const double ceilingDelta = 0.0004;
+        private const double ceilingExpectedResult = 2500;
+
+        public void Ceiling() => CeilingTest();
+
+        public static void CeilingTest()
+        {
+            double result = 0.0, value = -1.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += ceilingDelta;
+                result += Math.Ceiling(value);
+            }
+
+            double diff = Math.Abs(ceilingExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {ceilingExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/CopySignDouble.cs b/src/tests/JIT/Math/Functions/Double/CopySignDouble.cs
new file mode 100644 (file)
index 0000000..f3331e0
--- /dev/null
@@ -0,0 +1,34 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.CopySign(double) over 5000 iterations for the domain -1, +1
+
+        private const double copySignDelta = 0.0004;
+        private const int copySignExpectedResult = 0;
+
+        public void CopySign() => CopySignTest();
+
+        public static void CopySignTest()
+        {
+            double result = 1.0, value = -1.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += copySignDelta;
+                result += Math.CopySign(result, value);
+            }
+
+            if (result != copySignExpectedResult)
+            {
+                throw new Exception($"Expected Result {copySignExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/CosDouble.cs b/src/tests/JIT/Math/Functions/Double/CosDouble.cs
new file mode 100644 (file)
index 0000000..036d2ce
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Cos(double) over 5000 iterations for the domain 0, PI
+
+        private const double cosDoubleDelta = 0.0006283185307180;
+        private const double cosDoubleExpectedResult = -1.0000000005924159;
+
+        public void Cos() => CosDoubleTest();
+
+        public static void CosDoubleTest()
+        {
+            double result = 0.0, value = 0.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += cosDoubleDelta;
+                result += Math.Cos(value);
+            }
+
+            double diff = Math.Abs(cosDoubleExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {cosDoubleExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/CoshDouble.cs b/src/tests/JIT/Math/Functions/Double/CoshDouble.cs
new file mode 100644 (file)
index 0000000..bfa3108
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Cosh(double) over 5000 iterations for the domain -1, +1
+
+        private const double coshDelta = 0.0004;
+        private const double coshExpectedResult = 5876.0060465657216;
+
+        public void Cosh() => CoshTest();
+
+        public static void CoshTest()
+        {
+            double result = 0.0, value = -1.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += coshDelta;
+                result += Math.Cosh(value);
+            }
+
+            double diff = Math.Abs(coshExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {coshExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/ExpDouble.cs b/src/tests/JIT/Math/Functions/Double/ExpDouble.cs
new file mode 100644 (file)
index 0000000..1058097
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Exp(double) over 5000 iterations for the domain -1, +1
+
+        private const double expDelta = 0.0004;
+        private const double expExpectedResult = 5877.1812477590884;
+
+        public void Exp() => ExpTest();
+
+        public static void ExpTest()
+        {
+            double result = 0.0, value = -1.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += expDelta;
+                result += Math.Exp(value);
+            }
+
+            double diff = Math.Abs(expExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {expExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/FloorDouble.cs b/src/tests/JIT/Math/Functions/Double/FloorDouble.cs
new file mode 100644 (file)
index 0000000..b214466
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Floor(double) over 5000 iterations for the domain -1, +1
+
+        private const double floorDelta = 0.0004;
+        private const double floorExpectedResult = -2500;
+
+        public void Floor() => FloorTest();
+
+        public static void FloorTest()
+        {
+            double result = 0.0, value = -1.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += floorDelta;
+                result += Math.Floor(value);
+            }
+
+            double diff = Math.Abs(floorExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {floorExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/FusedMultiplyAdd.cs b/src/tests/JIT/Math/Functions/Double/FusedMultiplyAdd.cs
new file mode 100644 (file)
index 0000000..4d483ab
--- /dev/null
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.FusedMultiplyAdd(double, double, double) over 5000 iterations for the domain x: +2, +1; y: -2, -1, z: +1, -1
+
+        private const double fusedMultiplyAddDeltaX = -0.0004;
+        private const double fusedMultiplyAddDeltaY = 0.0004;
+        private const double fusedMultiplyAddDeltaZ = -0.0004;
+        private const double fusedMultiplyAddExpectedResult = -6667.6668000005066;
+
+        public void FusedMultiplyAdd() => FusedMultiplyAddTest();
+
+        public static void FusedMultiplyAddTest()
+        {
+            double result = 0.0, valueX = 2.0, valueY = -2.0, valueZ = 1.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                result += Math.FusedMultiplyAdd(valueX, valueY, valueZ);
+                valueX += fusedMultiplyAddDeltaX; valueY += fusedMultiplyAddDeltaY; valueZ += fusedMultiplyAddDeltaZ;
+            }
+
+            double diff = Math.Abs(fusedMultiplyAddExpectedResult - result);
+
+            if (double.IsNaN(result) || (diff > MathTests.DoubleEpsilon))
+            {
+                throw new Exception($"Expected Result {fusedMultiplyAddExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/ILogB.cs b/src/tests/JIT/Math/Functions/Double/ILogB.cs
new file mode 100644 (file)
index 0000000..5e8f50d
--- /dev/null
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.ILogB(double) over 5000 iterations for the domain +1, +3
+
+        private const double iLogBDelta = 0.0004;
+        private const int iLogBExpectedResult = 2499;
+
+        public void ILogB() => ILogBTest();
+
+        public static void ILogBTest()
+        {
+            int result = 0;
+            double value = 1.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                result += Math.ILogB(value);
+                value += iLogBDelta;
+            }
+
+            if (result != iLogBExpectedResult)
+            {
+                throw new Exception($"Expected Result {iLogBExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/Log10Double.cs b/src/tests/JIT/Math/Functions/Double/Log10Double.cs
new file mode 100644 (file)
index 0000000..0a90d9b
--- /dev/null
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Log10(double) over 5000 iterations for the domain -1, +1
+
+        private const double log10Delta = 0.0004;
+        private const double log10ExpectedResult = -664.07384902184072;
+
+        /// <summary>
+        /// this benchmark is dependent on loop alignment
+        /// </summary>
+        public void Log10() => Log10Test();
+
+        public static void Log10Test()
+        {
+            double result = 0.0, value = 0.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += log10Delta;
+                result += Math.Log10(value);
+            }
+
+            double diff = Math.Abs(log10ExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {log10ExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/Log2.cs b/src/tests/JIT/Math/Functions/Double/Log2.cs
new file mode 100644 (file)
index 0000000..1a8e020
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Log2(double) over 5000 iterations for the domain +1, +3
+
+        private const double log2Delta = 0.0004;
+        private const double log2ExpectedResult = 4672.9510376532398;
+
+        public void Log2() => Log2Test();
+
+        public static void Log2Test()
+        {
+            double result = 0.0, value = 1.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                result += Math.Log2(value);
+                value += log2Delta;
+            }
+
+            double diff = Math.Abs(log2ExpectedResult - result);
+
+            if (double.IsNaN(result) || (diff > MathTests.DoubleEpsilon))
+            {
+                throw new Exception($"Expected Result {log2ExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/LogDouble.cs b/src/tests/JIT/Math/Functions/Double/LogDouble.cs
new file mode 100644 (file)
index 0000000..f53f5e1
--- /dev/null
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Log(double) over 5000 iterations for the domain -1, +1
+
+        private const double logDelta = 0.0004;
+        private const double logExpectedResult = -1529.0865454048721;
+
+        public void Log() => LogTest();
+
+        public static void LogTest()
+        {
+            double result = 0.0, value = 0.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += logDelta;
+                result += Math.Log(value);
+            }
+
+            double diff = Math.Abs(logExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {logExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+
+}
diff --git a/src/tests/JIT/Math/Functions/Double/MaxDouble.cs b/src/tests/JIT/Math/Functions/Double/MaxDouble.cs
new file mode 100644 (file)
index 0000000..fe1d63c
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Min(double) over 5000 iterations for the domain -1, +1
+
+        private const double maxDelta = 0.0004;
+        private const double maxExpectedResult = -1.0;
+
+        public void Max() => MaxTest();
+
+        public static void MaxTest()
+        {
+            double result = 0.0, val1 = -1.0, val2 = -1.0 - maxDelta;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                val2 += maxDelta;
+                result += Math.Max(val1, val2);
+            }
+
+            double diff = Math.Abs(maxExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {maxExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/MinDouble.cs b/src/tests/JIT/Math/Functions/Double/MinDouble.cs
new file mode 100644 (file)
index 0000000..82e5bf4
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Min(double) over 5000 iterations for the domain -1, +1
+
+        private const double minDelta = 0.0004;
+        private const double minExpectedResult = 1.0;
+
+        public void Min() => MinTest();
+
+        public static void MinTest()
+        {
+            double result = 0.0, val1 = 1.0, val2 = 1.0 + minDelta;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                val2 -= minDelta;
+                result += Math.Min(val1, val2);
+            }
+
+            double diff = Math.Abs(minExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {minExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/PowDouble.cs b/src/tests/JIT/Math/Functions/Double/PowDouble.cs
new file mode 100644 (file)
index 0000000..c97e691
--- /dev/null
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Pow(double, double) over 5000 iterations for the domain x: +2, +1; y: -2, -1
+
+        private const double powDeltaX = -0.0004;
+        private const double powDeltaY = 0.0004;
+        private const double powExpectedResult = 4659.4627376138733;
+
+        public void Pow() => PowTest();
+
+        public static void PowTest()
+        {
+            double result = 0.0, valueX = 2.0, valueY = -2.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                valueX += powDeltaX; valueY += powDeltaY;
+                result += Math.Pow(valueX, valueY);
+            }
+
+            double diff = Math.Abs(powExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {powExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/RoundDouble.cs b/src/tests/JIT/Math/Functions/Double/RoundDouble.cs
new file mode 100644 (file)
index 0000000..790d32d
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Round(double) over 5000 iterations for the domain -PI/2, +PI/2
+
+        private const double roundDelta = 0.0006283185307180;
+        private const double roundExpectedResult = 2;
+
+        public void Round() => RoundTest();
+
+        public static void RoundTest()
+        {
+            double result = 0.0, value = -1.5707963267948966;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += roundDelta;
+                result += Math.Round(value);
+            }
+
+            double diff = Math.Abs(roundExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {roundExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/ScaleB.cs b/src/tests/JIT/Math/Functions/Double/ScaleB.cs
new file mode 100644 (file)
index 0000000..976d5fc
--- /dev/null
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.ScaleB(double, int) over 5000 iterations for the domain x: -1, +1; y: +0, +5000
+
+        private const double scaleBDeltaX = -0.0004;
+        private const int scaleBDeltaY = 1;
+        private const double scaleBExpectedResult = double.NegativeInfinity;
+
+        public void ScaleB() => ScaleBTest();
+
+        public static void ScaleBTest()
+        {
+            double result = 0.0, valueX = -1.0;
+            int valueY = 1;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                result += Math.ScaleB(valueX, valueY);
+                valueX += scaleBDeltaX; valueY += scaleBDeltaY;
+            }
+
+            double diff = Math.Abs(scaleBExpectedResult - result);
+
+            if (double.IsNaN(result) || (diff > MathTests.DoubleEpsilon))
+            {
+                throw new Exception($"Expected Result {scaleBExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/SinDouble.cs b/src/tests/JIT/Math/Functions/Double/SinDouble.cs
new file mode 100644 (file)
index 0000000..ba32fda
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Sin(double) over 5000 iterations for the domain -PI/2, +PI/2
+
+        private const double sinDelta = 0.0006283185307180;
+        private const double sinExpectedResult = 1.0000000005445053;
+
+        public void Sin() => SinTest();
+
+        public static void SinTest()
+        {
+            double result = 0.0, value = -1.5707963267948966;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += sinDelta;
+                result += Math.Sin(value);
+            }
+
+            double diff = Math.Abs(sinExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {sinExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/SinhDouble.cs b/src/tests/JIT/Math/Functions/Double/SinhDouble.cs
new file mode 100644 (file)
index 0000000..3d9c1d3
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Sinh(double) over 5000 iterations for the domain -1, +1
+
+        private const double sinhDelta = 0.0004;
+        private const double sinhExpectedResult = 1.17520119337903;
+
+        public void Sinh() => SinhTest();
+
+        public static void SinhTest()
+        {
+            double result = 0.0, value = -1.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += sinhDelta;
+                result += Math.Sinh(value);
+            }
+
+            double diff = Math.Abs(sinhExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {sinhExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/SqrtDouble.cs b/src/tests/JIT/Math/Functions/Double/SqrtDouble.cs
new file mode 100644 (file)
index 0000000..e30c86a
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Sqrt(double) over 5000 iterations for the domain 0, PI
+
+        private const double sqrtDelta = 0.0006283185307180;
+        private const double sqrtExpectedResult = 5909.0605337797215;
+
+        public void Sqrt() => SqrtTest();
+
+        public static void SqrtTest()
+        {
+            double result = 0.0, value = 0.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += sqrtDelta;
+                result += Math.Sqrt(value);
+            }
+
+            double diff = Math.Abs(sqrtExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {sqrtExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/TanDouble.cs b/src/tests/JIT/Math/Functions/Double/TanDouble.cs
new file mode 100644 (file)
index 0000000..844155b
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Tan(double) over 5000 iterations for the domain -PI/2, +PI/2
+
+        private const double tanDelta = 0.0004;
+        private const double tanExpectedResult = 1.5574077243051505;
+
+        public void Tan() => TanTest();
+
+        public static void TanTest()
+        {
+            double result = 0.0, value = -1.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += tanDelta;
+                result += Math.Tan(value);
+            }
+
+            double diff = Math.Abs(tanExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {tanExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Double/TanhDouble.cs b/src/tests/JIT/Math/Functions/Double/TanhDouble.cs
new file mode 100644 (file)
index 0000000..6ad7efa
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Double
+    {
+        // Tests Math.Tanh(double) over 5000 iterations for the domain -1, +1
+
+        private const double tanhDelta = 0.0004;
+        private const double tanhExpectedResult = 0.76159415578341827;
+
+        public void Tanh() => TanhTest();
+
+        public static void TanhTest()
+        {
+            double result = 0.0, value = -1.0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += tanhDelta;
+                result += Math.Tanh(value);
+            }
+
+            double diff = Math.Abs(tanhExpectedResult - result);
+
+            if (diff > MathTests.DoubleEpsilon)
+            {
+                throw new Exception($"Expected Result {tanhExpectedResult,20:g17}; Actual Result {result,20:g17}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Functions_r.csproj b/src/tests/JIT/Math/Functions/Functions_r.csproj
new file mode 100644 (file)
index 0000000..e61a28a
--- /dev/null
@@ -0,0 +1,12 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+  </PropertyGroup>
+  <PropertyGroup>
+    <DebugType>None</DebugType>
+    <Optimize />
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="**/*.cs" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/JIT/Math/Functions/Functions_ro.csproj b/src/tests/JIT/Math/Functions/Functions_ro.csproj
new file mode 100644 (file)
index 0000000..87bd76c
--- /dev/null
@@ -0,0 +1,12 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+  </PropertyGroup>
+  <PropertyGroup>
+    <DebugType>None</DebugType>
+    <Optimize>True</Optimize>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="**/*.cs" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/JIT/Math/Functions/MathTests.cs b/src/tests/JIT/Math/Functions/MathTests.cs
new file mode 100644 (file)
index 0000000..5b8da72
--- /dev/null
@@ -0,0 +1,29 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.MathBenchmarks
+{
+    public partial class MathTests
+    {
+        // double has a machine epsilon of approx: 2.22e-16. However, due to floating-point precision
+        // errors, this is too accurate when aggregating values of a set of iterations. Using the
+        // single-precision machine epsilon as our epsilon should be 'good enough' for the purposes
+        // of the perf testing as it ensures we get the expected value and that it is at least as precise
+        // as we would have computed with the single-precision version of the function (without aggregation).
+        public const double DoubleEpsilon = 1.19e-07;
+
+        // 5000 iterations is enough to cover the full domain of inputs for certain functions (such
+        // as Cos, which has a domain of 0 to PI) at reasonable intervals (in the case of Cos, the
+        // interval is PI / 5000 which is 0.0006283185307180). It should also give reasonable coverage
+        // for functions which have a larger domain (such as Atan, which covers the full set of real numbers).
+        public const int Iterations = 5000;
+
+        // float has a machine epsilon of approx: 1.19e-07. However, due to floating-point precision
+        // errors, this is too accurate when aggregating values of a set of iterations. Using the
+        // half-precision machine epsilon as our epsilon should be 'good enough' for the purposes
+        // of the perf testing as it ensures we get the expected value and that it is at least as precise
+        // as we would have computed with the half-precision version of the function (without aggregation).
+        public const float SingleEpsilon = 9.77e-04f;
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Program.cs b/src/tests/JIT/Math/Functions/Program.cs
new file mode 100644 (file)
index 0000000..ba502dd
--- /dev/null
@@ -0,0 +1,94 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.MathBenchmarks
+{
+    public partial class MathTests
+    {
+        public static int Main(string[] args)
+        {
+            var result = 100;
+
+            var doubleTests = new Double();
+            result += Test(doubleTests.Abs);
+            result += Test(doubleTests.Acos);
+            result += Test(doubleTests.Acosh);
+            result += Test(doubleTests.Asin);
+            result += Test(doubleTests.Asinh);
+            result += Test(doubleTests.Atan);
+            result += Test(doubleTests.Atanh);
+            result += Test(doubleTests.Atan2);
+            result += Test(doubleTests.Cbrt);
+            result += Test(doubleTests.Ceiling);
+            result += Test(doubleTests.CopySign);
+            result += Test(doubleTests.Cos);
+            result += Test(doubleTests.Cosh);
+            result += Test(doubleTests.Exp);
+            result += Test(doubleTests.Floor);
+            result += Test(doubleTests.FusedMultiplyAdd);
+            result += Test(doubleTests.ILogB);
+            result += Test(doubleTests.Log);
+            result += Test(doubleTests.Log2);
+            result += Test(doubleTests.Log10);
+            result += Test(doubleTests.Max);
+            result += Test(doubleTests.Min);
+            result += Test(doubleTests.Pow);
+            result += Test(doubleTests.Round);
+            result += Test(doubleTests.ScaleB);
+            result += Test(doubleTests.Sin);
+            result += Test(doubleTests.Sinh);
+            result += Test(doubleTests.Sqrt);
+            result += Test(doubleTests.Tan);
+            result += Test(doubleTests.Tanh);
+
+            var singleTests = new Single();
+            result += Test(singleTests.Abs);
+            result += Test(singleTests.Acos);
+            result += Test(singleTests.Acosh);
+            result += Test(singleTests.Asin);
+            result += Test(singleTests.Asinh);
+            result += Test(singleTests.Atan);
+            result += Test(singleTests.Atanh);
+            result += Test(singleTests.Atan2);
+            result += Test(singleTests.Cbrt);
+            result += Test(singleTests.Ceiling);
+            result += Test(singleTests.CopySign);
+            result += Test(singleTests.Cos);
+            result += Test(singleTests.Cosh);
+            result += Test(singleTests.Exp);
+            result += Test(singleTests.Floor);
+            result += Test(singleTests.FusedMultiplyAdd);
+            result += Test(singleTests.ILogB);
+            result += Test(singleTests.Log);
+            result += Test(singleTests.Log2);
+            result += Test(singleTests.Log10);
+            result += Test(singleTests.Max);
+            result += Test(singleTests.Min);
+            result += Test(singleTests.Pow);
+            result += Test(singleTests.Round);
+            result += Test(singleTests.ScaleB);
+            result += Test(singleTests.Sin);
+            result += Test(singleTests.Sinh);
+            result += Test(singleTests.Sqrt);
+            result += Test(singleTests.Tan);
+            result += Test(singleTests.Tanh);
+
+            return result;
+        }
+
+        private static int Test(Action action)
+        {
+            try
+            {
+                action();
+            }
+            catch
+            {
+                return -1;
+            }
+
+            return 0;
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/AbsSingle.cs b/src/tests/JIT/Math/Functions/Single/AbsSingle.cs
new file mode 100644 (file)
index 0000000..88c6cb9
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests Math.Abs(single) over 5000 iterations for the domain -1, +1
+
+        private const float absDelta = 0.0004f;
+        private const float absExpectedResult = 2500.03125f;
+
+        public void Abs() => AbsTest();
+
+        public static void AbsTest()
+        {
+            float result = 0.0f, value = -1.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += absDelta;
+                result += Math.Abs(value);
+            }
+
+            float diff = Math.Abs(absExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {absExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/AcosSingle.cs b/src/tests/JIT/Math/Functions/Single/AcosSingle.cs
new file mode 100644 (file)
index 0000000..322f703
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Acos(float) over 5000 iterations for the domain -1, +1
+
+        private const float acosDelta = 0.0004f;
+        private const float acosExpectedResult = 7852.41084f;
+
+        public void Acos() => AcosTest();
+
+        public static void AcosTest()
+        {
+            float result = 0.0f, value = -1.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += acosDelta;
+                result += MathF.Acos(value);
+            }
+
+            float diff = MathF.Abs(acosExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {acosExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/Acosh.cs b/src/tests/JIT/Math/Functions/Single/Acosh.cs
new file mode 100644 (file)
index 0000000..1ab4ac4
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Acosh(float) over 5000 iterations for the domain +1, +3
+
+        private const float acoshDelta = 0.0004f;
+        private const float acoshExpectedResult = 6148.45459f;
+
+        public void Acosh() => AcoshTest();
+
+        public static void AcoshTest()
+        {
+            float result = 0.0f, value = 1.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                result += MathF.Acosh(value);
+                value += acoshDelta;
+            }
+
+            float diff = MathF.Abs(acoshExpectedResult - result);
+
+            if (float.IsNaN(result) || (diff > MathTests.SingleEpsilon))
+            {
+                throw new Exception($"Expected Result {acoshExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/AsinSingle.cs b/src/tests/JIT/Math/Functions/Single/AsinSingle.cs
new file mode 100644 (file)
index 0000000..1982ae2
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Asin(float) over 5000 iterations for the domain -1, +1
+
+        private const float asinDelta = 0.0004f;
+        private const float asinExpectedResult = 1.57079590f;
+
+        public void Asin() => AsinTest();
+
+        public static void AsinTest()
+        {
+            float result = 0.0f, value = -1.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += asinDelta;
+                result += MathF.Asin(value);
+            }
+
+            float diff = MathF.Abs(asinExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {asinExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/Asinh.cs b/src/tests/JIT/Math/Functions/Single/Asinh.cs
new file mode 100644 (file)
index 0000000..8cb68d6
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Asinh(float) over 5000 iterations for the domain -1, +1
+
+        private const float asinhDelta = 0.0004f;
+        private const float asinhExpectedResult = -0.814757347f;
+
+        public void Asinh() => AsinhTest();
+
+        public static void AsinhTest()
+        {
+            float result = 0.0f, value = -1.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                result += MathF.Asinh(value);
+                value += asinhDelta;
+            }
+
+            float diff = MathF.Abs(asinhExpectedResult - result);
+
+            if (float.IsNaN(result) || (diff > MathTests.SingleEpsilon))
+            {
+                throw new Exception($"Expected Result {asinhExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/Atan2Single.cs b/src/tests/JIT/Math/Functions/Single/Atan2Single.cs
new file mode 100644 (file)
index 0000000..9068226
--- /dev/null
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Atan2(float, float) over 5000 iterations for the domain y: -1, +1; x: +1, -1
+
+        private const float atan2DeltaX = -0.0004f;
+        private const float atan2DeltaY = 0.0004f;
+        private const float atan2ExpectedResult = 3930.14282f;
+
+        public void Atan2() => Atan2Test();
+
+        public static void Atan2Test()
+        {
+            float result = 0.0f, valueX = 1.0f, valueY = -1.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                valueX += atan2DeltaX; valueY += atan2DeltaY;
+                result += MathF.Atan2(valueY, valueX);
+            }
+
+            float diff = MathF.Abs(atan2ExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {atan2ExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/AtanSingle.cs b/src/tests/JIT/Math/Functions/Single/AtanSingle.cs
new file mode 100644 (file)
index 0000000..8e9fc11
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Atan(float) over 5000 iterations for the domain -1, +1
+
+        private const float atanDelta = 0.0004f;
+        private const float atanExpectedResult = 0.841940999f;
+
+        public void Atan() => AtanTest();
+
+        public static void AtanTest()
+        {
+            float result = 0.0f, value = -1.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += atanDelta;
+                result += MathF.Atan(value);
+            }
+
+            float diff = MathF.Abs(atanExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {atanExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/Atanh.cs b/src/tests/JIT/Math/Functions/Single/Atanh.cs
new file mode 100644 (file)
index 0000000..b5d2063
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Atanh(float) over 5000 iterations for the domain -1, +1
+
+        private const float atanhDelta = 0.0004f;
+        private const float atanhExpectedResult = float.NegativeInfinity;
+
+        public void Atanh() => AtanhTest();
+
+        public static void AtanhTest()
+        {
+            float result = 0.0f, value = -1.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                result += MathF.Atanh(value);
+                value += atanhDelta;
+            }
+
+            float diff = MathF.Abs(atanhExpectedResult - result);
+
+            if (float.IsNaN(result) || (diff > MathTests.SingleEpsilon))
+            {
+                throw new Exception($"Expected Result {atanhExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/Cbrt.cs b/src/tests/JIT/Math/Functions/Single/Cbrt.cs
new file mode 100644 (file)
index 0000000..fd8df18
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Cbrt(float) over 5000 iterations for the domain +0, +PI
+
+        private const float cbrtDelta = 0.000628318531f;
+        private const float cbrtExpectedResult = 5491.4541f;
+
+        public void Cbrt() => CbrtTest();
+
+        public static void CbrtTest()
+        {
+            float result = 0.0f, value = 0.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                result += MathF.Cbrt(value);
+                value += cbrtDelta;
+            }
+
+            float diff = MathF.Abs(cbrtExpectedResult - result);
+
+            if (float.IsNaN(result) || (diff > MathTests.SingleEpsilon))
+            {
+                throw new Exception($"Expected Result {cbrtExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/CeilingSingle.cs b/src/tests/JIT/Math/Functions/Single/CeilingSingle.cs
new file mode 100644 (file)
index 0000000..ed36615
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Ceiling(float) over 5000 iterations for the domain -1, +1
+
+        private const float ceilingDelta = 0.0004f;
+        private const float ceilingExpectedResult = 2502.0f;
+
+        public void Ceiling() => CeilingTest();
+
+        public static void CeilingTest()
+        {
+            float result = 0.0f, value = -1.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += ceilingDelta;
+                result += MathF.Ceiling(value);
+            }
+
+            float diff = MathF.Abs(ceilingExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {ceilingExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/CopySignSingle.cs b/src/tests/JIT/Math/Functions/Single/CopySignSingle.cs
new file mode 100644 (file)
index 0000000..5a0c357
--- /dev/null
@@ -0,0 +1,34 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests Math.CopySign(float) over 5000 iterations for the domain -1, +1
+
+        private const float copySignDelta = 0.0004f;
+        private const int copySignExpectedResult = 0;
+
+        public void CopySign() => CopySignTest();
+
+        public static void CopySignTest()
+        {
+            float result = 1.0f, value = -1.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += copySignDelta;
+                result += MathF.CopySign(result, value);
+            }
+
+            if (result != copySignExpectedResult)
+            {
+                throw new Exception($"Expected Result {copySignExpectedResult}; Actual Result {result}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/CosSingle.cs b/src/tests/JIT/Math/Functions/Single/CosSingle.cs
new file mode 100644 (file)
index 0000000..f27428f
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Cos(float) over 5000 iterations for the domain 0, PI
+
+        private const float cosDelta = 0.000628318531f;
+        private const float cosExpectedResult = -0.993487537f;
+
+        public void Cos() => CosTest();
+
+        public static void CosTest()
+        {
+            float result = 0.0f, value = 0.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += cosDelta;
+                result += MathF.Cos(value);
+            }
+
+            float diff = MathF.Abs(cosExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {cosExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/CoshSingle.cs b/src/tests/JIT/Math/Functions/Single/CoshSingle.cs
new file mode 100644 (file)
index 0000000..f326bde
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Cosh(float) over 5000 iterations for the domain -1, +1
+
+        private const float coshDelta = 0.0004f;
+        private const float coshExpectedResult = 5876.02588f;
+
+        public void Cosh() => CoshTest();
+
+        public static void CoshTest()
+        {
+            float result = 0.0f, value = -1.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += coshDelta;
+                result += MathF.Cosh(value);
+            }
+
+            float diff = MathF.Abs(coshExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {coshExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/ExpSingle.cs b/src/tests/JIT/Math/Functions/Single/ExpSingle.cs
new file mode 100644 (file)
index 0000000..3d5010f
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Exp(float) over 5000 iterations for the domain -1, +1
+
+        private const float expDelta = 0.0004f;
+        private const float expExpectedResult = 5877.28564f;
+
+        public void Exp() => ExpTest();
+
+        public static void ExpTest()
+        {
+            float result = 0.0f, value = -1.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += expDelta;
+                result += MathF.Exp(value);
+            }
+
+            float diff = MathF.Abs(expExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {expExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/FloorSingle.cs b/src/tests/JIT/Math/Functions/Single/FloorSingle.cs
new file mode 100644 (file)
index 0000000..5baa87f
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Floor(float) over 5000 iterations for the domain -1, +1
+
+        private const float floorDelta = 0.0004f;
+        private const float floorExpectedResult = -2498.0f;
+
+        public void Floor() => FloorTest();
+
+        public static void FloorTest()
+        {
+            float result = 0.0f, value = -1.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += floorDelta;
+                result += MathF.Floor(value);
+            }
+
+            float diff = MathF.Abs(floorExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {floorExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/FusedMultiplyAdd.cs b/src/tests/JIT/Math/Functions/Single/FusedMultiplyAdd.cs
new file mode 100644 (file)
index 0000000..d2dd322
--- /dev/null
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.FusedMultiplyAdd(float, float, float) over 5000 iterations for the domain x: +2, +1; y: -2, -1, z: +1, -1
+
+        private const float fusedMultiplyAddDeltaX = -0.0004f;
+        private const float fusedMultiplyAddDeltaY = 0.0004f;
+        private const float fusedMultiplyAddDeltaZ = -0.0004f;
+        private const float fusedMultiplyAddExpectedResult = -6668.49072f;
+
+        public void FusedMultiplyAdd() => FusedMultiplyAddTest();
+
+        public static void FusedMultiplyAddTest()
+        {
+            float result = 0.0f, valueX = 2.0f, valueY = -2.0f, valueZ = 1.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                result += MathF.FusedMultiplyAdd(valueX, valueY, valueZ);
+                valueX += fusedMultiplyAddDeltaX; valueY += fusedMultiplyAddDeltaY; valueZ += fusedMultiplyAddDeltaZ;
+            }
+
+            float diff = MathF.Abs(fusedMultiplyAddExpectedResult - result);
+
+            if (float.IsNaN(result) || (diff > MathTests.SingleEpsilon))
+            {
+                throw new Exception($"Expected Result {fusedMultiplyAddExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/ILogB.cs b/src/tests/JIT/Math/Functions/Single/ILogB.cs
new file mode 100644 (file)
index 0000000..4361ec5
--- /dev/null
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.ILogB(float) over 5000 iterations for the domain +1, +3
+
+        private const float iLogBDelta = 0.0004f;
+        private const int iLogBExpectedResult = 2499;
+
+        public void ILogB() => ILogBTest();
+
+        public static void ILogBTest()
+        {
+            int result = 0;
+            float value = 1.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                result += MathF.ILogB(value);
+                value += iLogBDelta;
+            }
+
+            if (result != iLogBExpectedResult)
+            {
+                throw new Exception($"Expected Result {iLogBExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/Log10Single.cs b/src/tests/JIT/Math/Functions/Single/Log10Single.cs
new file mode 100644 (file)
index 0000000..6f4617f
--- /dev/null
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Log10(float) over 5000 iterations for the domain -1, +1
+
+        private const float log10Delta = 0.0004f;
+        private const float log10ExpectedResult = -664.094971f;
+
+        /// <summary>
+        /// this benchmark is dependent on loop alignment
+        /// </summary>
+        public void Log10() => Log10Test();
+
+        public static void Log10Test()
+        {
+            float result = 0.0f, value = 0.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += log10Delta;
+                result += MathF.Log10(value);
+            }
+
+            float diff = MathF.Abs(log10ExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {log10ExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/Log2.cs b/src/tests/JIT/Math/Functions/Single/Log2.cs
new file mode 100644 (file)
index 0000000..4da7d7a
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Log2(float) over 5000 iterations for the domain +1, +3
+
+        private const float log2Delta = 0.0004f;
+        private const float log2ExpectedResult = 4672.73193f;
+
+        public void Log2() => Log2Test();
+
+        public static void Log2Test()
+        {
+            float result = 0.0f, value = 1.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                result += MathF.Log2(value);
+                value += log2Delta;
+            }
+
+            float diff = MathF.Abs(log2ExpectedResult - result);
+
+            if (float.IsNaN(result) || (diff > MathTests.SingleEpsilon))
+            {
+                throw new Exception($"Expected Result {log2ExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/LogSingle.cs b/src/tests/JIT/Math/Functions/Single/LogSingle.cs
new file mode 100644 (file)
index 0000000..ed52674
--- /dev/null
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Log(float) over 5000 iterations for the domain -1, +1
+
+        private const float logDelta = 0.0004f;
+        private const float logExpectedResult = -1529.14014f;
+
+        public void Log() => LogTest();
+
+        public static void LogTest()
+        {
+            float result = 0.0f, value = 0.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += logDelta;
+                result += MathF.Log(value);
+            }
+
+            float diff = MathF.Abs(logExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {logExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+
+}
diff --git a/src/tests/JIT/Math/Functions/Single/MaxSingle.cs b/src/tests/JIT/Math/Functions/Single/MaxSingle.cs
new file mode 100644 (file)
index 0000000..923b327
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests Math.Min(double) over 5000 iterations for the domain -1, +1
+
+        private const float maxDelta = 0.0004f;
+        private const float maxExpectedResult = -0.9267354f;
+
+        public void Max() => MaxTest();
+
+        public static void MaxTest()
+        {
+            float result = 0.0f, val1 = -1.0f, val2 = -1.0f - maxDelta;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                val2 += maxDelta;
+                result += Math.Max(val1, val2);
+            }
+
+            float diff = Math.Abs(maxExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {maxExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/MinSingle.cs b/src/tests/JIT/Math/Functions/Single/MinSingle.cs
new file mode 100644 (file)
index 0000000..436f6ff
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests Math.Min(double) over 5000 iterations for the domain -1, +1
+
+        private const float minDelta = 0.0004f;
+        private const float minExpectedResult = 0.9267354f;
+
+        public void Min() => MinTest();
+
+        public static void MinTest()
+        {
+            float result = 0.0f, val1 = 1.0f, val2 = 1.0f + minDelta;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                val2 -= minDelta;
+                result += Math.Min(val1, val2);
+            }
+
+            float diff = Math.Abs(minExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {minExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/PowSingle.cs b/src/tests/JIT/Math/Functions/Single/PowSingle.cs
new file mode 100644 (file)
index 0000000..0517dfa
--- /dev/null
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Pow(float, float) over 5000 iterations for the domain x: +2, +1; y: -2, -1
+
+        private const float powDeltaX = -0.0004f;
+        private const float powDeltaY = 0.0004f;
+        private const float powExpectedResult = 4659.30762f;
+
+        public void Pow() => PowTest();
+
+        public static void PowTest()
+        {
+            float result = 0.0f, valueX = 2.0f, valueY = -2.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                valueX += powDeltaX; valueY += powDeltaY;
+                result += MathF.Pow(valueX, valueY);
+            }
+
+            float diff = MathF.Abs(powExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {powExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/RoundSingle.cs b/src/tests/JIT/Math/Functions/Single/RoundSingle.cs
new file mode 100644 (file)
index 0000000..cb92704
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Round(float) over 5000 iterations for the domain -PI/2, +PI/2
+
+        private const float roundDelta = 0.000628318531f;
+        private const float roundExpectedResult = 2.0f;
+
+        public void Round() => RoundTest();
+
+        public static void RoundTest()
+        {
+            float result = 0.0f, value = -1.57079633f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += roundDelta;
+                result += MathF.Round(value);
+            }
+
+            float diff = MathF.Abs(roundExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {roundExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/ScaleB.cs b/src/tests/JIT/Math/Functions/Single/ScaleB.cs
new file mode 100644 (file)
index 0000000..4a9a089
--- /dev/null
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.ScaleB(float, int) over 5000 iterations for the domain x: -1, +1; y: +0, +5000
+
+        private const float scaleBDeltaX = -0.0004f;
+        private const int scaleBDeltaY = 1;
+        private const float scaleBExpectedResult = float.NegativeInfinity;
+
+        public void ScaleB() => ScaleBTest();
+
+         public static void ScaleBTest()
+        {
+            float result = 0.0f, valueX = -1.0f;
+            int valueY = 0;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                result += MathF.ScaleB(valueX, valueY);
+                valueX += scaleBDeltaX; valueY += scaleBDeltaY;
+            }
+
+            float diff = MathF.Abs(scaleBExpectedResult - result);
+
+            if (float.IsNaN(result) || (diff > MathTests.SingleEpsilon))
+            {
+                throw new Exception($"Expected Result {scaleBExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/SinSingle.cs b/src/tests/JIT/Math/Functions/Single/SinSingle.cs
new file mode 100644 (file)
index 0000000..7b4c727
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Sin(float) over 5000 iterations for the domain -PI/2, +PI/2
+
+        private const float sinDelta = 0.000628318531f;
+        private const float sinExpectedResult = 1.03592682f;
+
+        public void Sin() => SinTest();
+
+        public static void SinTest()
+        {
+            float result = 0.0f, value = -1.57079633f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += sinDelta;
+                result += MathF.Sin(value);
+            }
+
+            float diff = MathF.Abs(sinExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {sinExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/SinhSingle.cs b/src/tests/JIT/Math/Functions/Single/SinhSingle.cs
new file mode 100644 (file)
index 0000000..ed5fb96
--- /dev/null
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Sinh(float) over 5000 iterations for the domain -1, +1
+
+        private const float sinhDelta = 0.0004f;
+        private const float sinhExpectedResult = 1.26028216f;
+
+        /// <summary>
+        /// this benchmark is dependent on loop alignment
+        /// </summary>
+        public void Sinh() => SinhTest();
+
+        public static void SinhTest()
+        {
+            float result = 0.0f, value = -1.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += sinhDelta;
+                result += MathF.Sinh(value);
+            }
+
+            float diff = MathF.Abs(sinhExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {sinhExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/SqrtSingle.cs b/src/tests/JIT/Math/Functions/Single/SqrtSingle.cs
new file mode 100644 (file)
index 0000000..2d80d67
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Sqrt(float) over 5000 iterations for the domain 0, PI
+
+        private const float sqrtDelta = 0.000628318531f;
+        private const float sqrtExpectedResult = 5909.03027f;
+
+        public void Sqrt() => SqrtTest();
+
+        public static void SqrtTest()
+        {
+            float result = 0.0f, value = 0.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += sqrtDelta;
+                result += MathF.Sqrt(value);
+            }
+
+            float diff = MathF.Abs(sqrtExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {sqrtExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/TanSingle.cs b/src/tests/JIT/Math/Functions/Single/TanSingle.cs
new file mode 100644 (file)
index 0000000..284de8b
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Tan(float) over 5000 iterations for the domain -PI/2, +PI/2
+
+        private const float tanDelta = 0.0004f;
+        private const float tanExpectedResult = 1.66717815f;
+
+        public void Tan() => TanTest();
+
+        public static void TanTest()
+        {
+            float result = 0.0f, value = -1.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += tanDelta;
+                result += MathF.Tan(value);
+            }
+
+            float diff = MathF.Abs(tanExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {tanExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}
diff --git a/src/tests/JIT/Math/Functions/Single/TanhSingle.cs b/src/tests/JIT/Math/Functions/Single/TanhSingle.cs
new file mode 100644 (file)
index 0000000..3674cef
--- /dev/null
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.MathBenchmarks
+{
+    public partial class Single
+    {
+        // Tests MathF.Tanh(float) over 5000 iterations for the domain -1, +1
+
+        private const float tanhDelta = 0.0004f;
+        private const float tanhExpectedResult = 0.816701353f;
+
+        public void Tanh() => TanhTest();
+
+        public static void TanhTest()
+        {
+            float result = 0.0f, value = -1.0f;
+
+            for (int iteration = 0; iteration < MathTests.Iterations; iteration++)
+            {
+                value += tanhDelta;
+                result += MathF.Tanh(value);
+            }
+
+            float diff = MathF.Abs(tanhExpectedResult - result);
+
+            if (diff > MathTests.SingleEpsilon)
+            {
+                throw new Exception($"Expected Result {tanhExpectedResult,10:g9}; Actual Result {result,10:g9}");
+            }
+        }
+    }
+}