From 55726fa43e0b3e28c04ef2922c26221579f6f815 Mon Sep 17 00:00:00 2001 From: Michael Sharp <51342856+michaelgsharp@users.noreply.github.com> Date: Fri, 25 Aug 2023 14:20:08 -0600 Subject: [PATCH] New Microsoft.BCL.Numerics package (#91074) * bcl numberics library added * bcl done * added explicit 2.1 target * Minor doc updates * Apply suggestions from code review Co-authored-by: Viktor Hofer * fixes from PR comments * minor csproj fixes * fixed ref target frameworks * minor ref csproj updates * minor csproj updates --------- Co-authored-by: Viktor Hofer --- .../Microsoft.Bcl.Numerics.sln | 74 ++ .../ref/Microsoft.Bcl.Numerics.Forwards.cs | 4 + .../ref/Microsoft.Bcl.Numerics.cs | 42 + .../ref/Microsoft.Bcl.Numerics.csproj | 12 + .../src/Microsoft.Bcl.Numerics.csproj | 24 + .../src/System/MathF.cs | 332 +++++ .../System/Microsoft.Bcl.Numerics.Forwards.cs | 4 + .../Microsoft.Bcl.Numerics/tests/MathF.cs | 1151 +++++++++++++++++ .../tests/Microsoft.Bcl.Numerics.Tests.csproj | 15 + 9 files changed, 1658 insertions(+) create mode 100644 src/libraries/Microsoft.Bcl.Numerics/Microsoft.Bcl.Numerics.sln create mode 100644 src/libraries/Microsoft.Bcl.Numerics/ref/Microsoft.Bcl.Numerics.Forwards.cs create mode 100644 src/libraries/Microsoft.Bcl.Numerics/ref/Microsoft.Bcl.Numerics.cs create mode 100644 src/libraries/Microsoft.Bcl.Numerics/ref/Microsoft.Bcl.Numerics.csproj create mode 100644 src/libraries/Microsoft.Bcl.Numerics/src/Microsoft.Bcl.Numerics.csproj create mode 100644 src/libraries/Microsoft.Bcl.Numerics/src/System/MathF.cs create mode 100644 src/libraries/Microsoft.Bcl.Numerics/src/System/Microsoft.Bcl.Numerics.Forwards.cs create mode 100644 src/libraries/Microsoft.Bcl.Numerics/tests/MathF.cs create mode 100644 src/libraries/Microsoft.Bcl.Numerics/tests/Microsoft.Bcl.Numerics.Tests.csproj diff --git a/src/libraries/Microsoft.Bcl.Numerics/Microsoft.Bcl.Numerics.sln b/src/libraries/Microsoft.Bcl.Numerics/Microsoft.Bcl.Numerics.sln new file mode 100644 index 0000000000000..1192785b14a9f --- /dev/null +++ b/src/libraries/Microsoft.Bcl.Numerics/Microsoft.Bcl.Numerics.sln @@ -0,0 +1,74 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{CAEE0409-CCC3-4EA6-AB54-177FD305D42D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bcl.Numerics", "ref\Microsoft.Bcl.Numerics.csproj", "{73E7C25C-AEBC-4F4F-B8D1-0CC49D5B92DE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bcl.Numerics", "src\Microsoft.Bcl.Numerics.csproj", "{4D4BED71-8904-4A74-88CD-63D002CCACD0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bcl.Numerics.Tests", "tests\Microsoft.Bcl.Numerics.Tests.csproj", "{51D9518A-464D-4257-9567-3BDCFF24F3EE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComInterfaceGenerator", "..\System.Runtime.InteropServices\gen\ComInterfaceGenerator\ComInterfaceGenerator.csproj", "{E30F71EB-6C3B-4052-84F7-36EAA178A45E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibraryImportGenerator", "..\System.Runtime.InteropServices\gen\LibraryImportGenerator\LibraryImportGenerator.csproj", "{0AE44453-273B-4F0E-9901-A87891A73C1B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Interop.SourceGeneration", "..\System.Runtime.InteropServices\gen\Microsoft.Interop.SourceGeneration\Microsoft.Interop.SourceGeneration.csproj", "{D0F1936C-CF7C-4448-9F90-B9DEABE89EBB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{6614EF7F-23FC-4809-AFF5-1ADBF1B6422C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{111B1B5B-A004-4C05-9A8C-E0931DADA5FB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{85204CF5-0C88-4BBB-9E70-D8CCED82ED3D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{D6A9108E-553B-445E-A037-FA4F3140A279}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CAEE0409-CCC3-4EA6-AB54-177FD305D42D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CAEE0409-CCC3-4EA6-AB54-177FD305D42D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CAEE0409-CCC3-4EA6-AB54-177FD305D42D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CAEE0409-CCC3-4EA6-AB54-177FD305D42D}.Release|Any CPU.Build.0 = Release|Any CPU + {73E7C25C-AEBC-4F4F-B8D1-0CC49D5B92DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {73E7C25C-AEBC-4F4F-B8D1-0CC49D5B92DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {73E7C25C-AEBC-4F4F-B8D1-0CC49D5B92DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {73E7C25C-AEBC-4F4F-B8D1-0CC49D5B92DE}.Release|Any CPU.Build.0 = Release|Any CPU + {4D4BED71-8904-4A74-88CD-63D002CCACD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D4BED71-8904-4A74-88CD-63D002CCACD0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D4BED71-8904-4A74-88CD-63D002CCACD0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D4BED71-8904-4A74-88CD-63D002CCACD0}.Release|Any CPU.Build.0 = Release|Any CPU + {51D9518A-464D-4257-9567-3BDCFF24F3EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {51D9518A-464D-4257-9567-3BDCFF24F3EE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {51D9518A-464D-4257-9567-3BDCFF24F3EE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {51D9518A-464D-4257-9567-3BDCFF24F3EE}.Release|Any CPU.Build.0 = Release|Any CPU + {E30F71EB-6C3B-4052-84F7-36EAA178A45E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E30F71EB-6C3B-4052-84F7-36EAA178A45E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E30F71EB-6C3B-4052-84F7-36EAA178A45E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E30F71EB-6C3B-4052-84F7-36EAA178A45E}.Release|Any CPU.Build.0 = Release|Any CPU + {0AE44453-273B-4F0E-9901-A87891A73C1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0AE44453-273B-4F0E-9901-A87891A73C1B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0AE44453-273B-4F0E-9901-A87891A73C1B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0AE44453-273B-4F0E-9901-A87891A73C1B}.Release|Any CPU.Build.0 = Release|Any CPU + {D0F1936C-CF7C-4448-9F90-B9DEABE89EBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D0F1936C-CF7C-4448-9F90-B9DEABE89EBB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D0F1936C-CF7C-4448-9F90-B9DEABE89EBB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D0F1936C-CF7C-4448-9F90-B9DEABE89EBB}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {CAEE0409-CCC3-4EA6-AB54-177FD305D42D} = {6614EF7F-23FC-4809-AFF5-1ADBF1B6422C} + {51D9518A-464D-4257-9567-3BDCFF24F3EE} = {6614EF7F-23FC-4809-AFF5-1ADBF1B6422C} + {73E7C25C-AEBC-4F4F-B8D1-0CC49D5B92DE} = {111B1B5B-A004-4C05-9A8C-E0931DADA5FB} + {4D4BED71-8904-4A74-88CD-63D002CCACD0} = {85204CF5-0C88-4BBB-9E70-D8CCED82ED3D} + {E30F71EB-6C3B-4052-84F7-36EAA178A45E} = {D6A9108E-553B-445E-A037-FA4F3140A279} + {0AE44453-273B-4F0E-9901-A87891A73C1B} = {D6A9108E-553B-445E-A037-FA4F3140A279} + {D0F1936C-CF7C-4448-9F90-B9DEABE89EBB} = {D6A9108E-553B-445E-A037-FA4F3140A279} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A835CEDB-E9E2-49EE-8499-BD7FDD984E53} + EndGlobalSection +EndGlobal diff --git a/src/libraries/Microsoft.Bcl.Numerics/ref/Microsoft.Bcl.Numerics.Forwards.cs b/src/libraries/Microsoft.Bcl.Numerics/ref/Microsoft.Bcl.Numerics.Forwards.cs new file mode 100644 index 0000000000000..641ce5525675f --- /dev/null +++ b/src/libraries/Microsoft.Bcl.Numerics/ref/Microsoft.Bcl.Numerics.Forwards.cs @@ -0,0 +1,4 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.MathF))] diff --git a/src/libraries/Microsoft.Bcl.Numerics/ref/Microsoft.Bcl.Numerics.cs b/src/libraries/Microsoft.Bcl.Numerics/ref/Microsoft.Bcl.Numerics.cs new file mode 100644 index 0000000000000..d952814464f67 --- /dev/null +++ b/src/libraries/Microsoft.Bcl.Numerics/ref/Microsoft.Bcl.Numerics.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ + +namespace System +{ + public static partial class MathF + { + public const float E = 2.7182817f; + public const float PI = 3.1415927f; + public static float Abs(float x) { throw null; } + public static float Acos(float x) { throw null; } + public static float Asin(float x) { throw null; } + public static float Atan(float x) { throw null; } + public static float Atan2(float y, float x) { throw null; } + public static float Ceiling(float x) { throw null; } + public static float Cos(float x) { throw null; } + public static float Cosh(float x) { throw null; } + public static float Exp(float x) { throw null; } + public static float Floor(float x) { throw null; } + public static float IEEERemainder(float x, float y) { throw null; } + public static float Log(float x) { throw null; } + public static float Log(float x, float y) { throw null; } + public static float Log10(float x) { throw null; } + public static float Max(float x, float y) { throw null; } + public static float Min(float x, float y) { throw null; } + public static float Pow(float x, float y) { throw null; } + public static float Round(float x) { throw null; } + public static float Round(float x, int digits) { throw null; } + public static float Round(float x, int digits, System.MidpointRounding mode) { throw null; } + public static float Round(float x, System.MidpointRounding mode) { throw null; } + public static int Sign(float x) { throw null; } + public static float Sin(float x) { throw null; } + public static float Sinh(float x) { throw null; } + public static float Sqrt(float x) { throw null; } + public static float Tan(float x) { throw null; } + public static float Tanh(float x) { throw null; } + public static float Truncate(float x) { throw null; } + } +} diff --git a/src/libraries/Microsoft.Bcl.Numerics/ref/Microsoft.Bcl.Numerics.csproj b/src/libraries/Microsoft.Bcl.Numerics/ref/Microsoft.Bcl.Numerics.csproj new file mode 100644 index 0000000000000..36d3ac9605c19 --- /dev/null +++ b/src/libraries/Microsoft.Bcl.Numerics/ref/Microsoft.Bcl.Numerics.csproj @@ -0,0 +1,12 @@ + + + + netstandard2.0;$(NetFrameworkMinimum);netstandard2.1 + + + + + + + + diff --git a/src/libraries/Microsoft.Bcl.Numerics/src/Microsoft.Bcl.Numerics.csproj b/src/libraries/Microsoft.Bcl.Numerics/src/Microsoft.Bcl.Numerics.csproj new file mode 100644 index 0000000000000..5d6b96dc6a29a --- /dev/null +++ b/src/libraries/Microsoft.Bcl.Numerics/src/Microsoft.Bcl.Numerics.csproj @@ -0,0 +1,24 @@ + + + + netstandard2.0;$(NetFrameworkMinimum);netstandard2.1 + true + true + + + Provides the System.MathF for .NET Standard 2.0 + + true + + + + + + + + + + + diff --git a/src/libraries/Microsoft.Bcl.Numerics/src/System/MathF.cs b/src/libraries/Microsoft.Bcl.Numerics/src/System/MathF.cs new file mode 100644 index 0000000000000..128a3174ad0c4 --- /dev/null +++ b/src/libraries/Microsoft.Bcl.Numerics/src/System/MathF.cs @@ -0,0 +1,332 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*============================================================ +** +** Purpose: Some single-precision floating-point math operations +** +===========================================================*/ + +//This class contains only static members and doesn't require serialization. + +//For most of this implementation for .NET Framework we just defer to System.Math and do a cast internally from single to double. +//We do this because it safer and less likely to break people since that is what they are alrady doing. Also, adding in the +//extra pinvokes needed to not do this route would probably incur an extra overhead that would be undersired. + +//For any version of .NET Core this just forwards directly to the MathF implementation inside the runtime. + +//There are a few cases where .NET Framework handles things differently than .NET Core does. For example, it returns -0 and +0 +//when using things like Min/Max, and they count as different values from each other. This is fixed in .NET Core, but since its +//inherent in .NET Framework we decided to leave that behavior as is for this BCL. + +using System.Diagnostics.Contracts; + +namespace System +{ + /// + /// Provides constants and static methods for trigonometric, logarithmic, and other common mathematical functions. + /// + public static class MathF + { + /// + /// Represents the ratio of the circumference of a circle to its diameter, specified by the constant, p. + /// + public const float PI = 3.14159265f; + + /// + /// Represents the natural logarithmic base, specified by the constant, e. + /// + public const float E = 2.71828183f; + + private static float NegativeZero = Int32BitsToSingle(unchecked((int)0x80000000)); + + private static unsafe float Int32BitsToSingle(int value) + { + return *((float*)&value); + } + + [Pure] + private static unsafe bool IsNegative(float f) + { + return (*(uint*)(&f) & 0x80000000) == 0x80000000; + } + + /// + /// Returns the absolute value of a single-precision floating-point number. + /// + /// The number to take the absolute value of. + /// The absolute value of + public static float Abs(float x) => Math.Abs(x); + + /// + /// Returns the angle whose cosine is the specified number. + /// + /// The number to take the acos of. + /// The acos of + public static float Acos(float x) => (float)Math.Acos(x); + + /// + /// Returns the angle whose sine is the specified number. + /// + /// The number to take the asin of. + /// The asin of + public static float Asin(float x) => (float)Math.Asin(x); + + /// + /// Returns the angle whose tangent is the specified number. + /// + /// The number to take the atan of. + /// The atan of + public static float Atan(float x) => (float)Math.Atan(x); + + /// + /// Returns the angle whose tangent is the quotient of two specified numbers. + /// + /// The first number. + /// The second number. + /// The angle whose tangent is the quotient of and + public static float Atan2(float y, float x) => (float)Math.Atan2(y, x); + + /// + /// Returns the smallest integral value that is greater than or equal to the specified single-precision floating-point number. + /// + /// The number to take the ceiling of. + /// The ceiling of + public static float Ceiling(float x) => (float)Math.Ceiling(x); + + /// + /// Returns the cosine of the specified angle. + /// + /// The angle to take the cosine of. + /// The cosine of + public static float Cos(float x) => (float)Math.Cos(x); + + /// + /// Returns the hyperbolic cosine of the specified angle. + /// + /// The angle to take the hyperbolic cosine of. + /// The hyperbolic cosine of + public static float Cosh(float x) => (float)Math.Cosh(x); + + /// + /// Returns e raised to the specified power. + /// + /// The number to raise e to. + /// e raised to the power of + public static float Exp(float x) => (float)Math.Exp(x); + + /// + /// Returns the largest integral value less than or equal to the specified single-precision floating-point number. + /// + /// The number to take the floor of. + /// The floor of + public static float Floor(float x) => (float)Math.Floor(x); + + /// + /// Returns the remainder resulting from the division of a specified number by another specified number. + /// + /// The numerator + /// The denominator + /// The result of dividing by + public static float IEEERemainder(float x, float y) + { + if (float.IsNaN(x)) + { + return x; // IEEE 754-2008: NaN payload must be preserved + } + + if (float.IsNaN(y)) + { + return y; // IEEE 754-2008: NaN payload must be preserved + } + + var regularMod = x % y; + + if (float.IsNaN(regularMod)) + { + return float.NaN; + } + + if ((regularMod == 0) && IsNegative(x)) + { + return NegativeZero; + } + + var alternativeResult = (regularMod - (Abs(y) * Sign(x))); + + if (Abs(alternativeResult) == Abs(regularMod)) + { + var divisionResult = x / y; + var roundedResult = Round(divisionResult); + + if (Abs(roundedResult) > Abs(divisionResult)) + { + return alternativeResult; + } + else + { + return regularMod; + } + } + + if (Abs(alternativeResult) < Abs(regularMod)) + { + return alternativeResult; + } + else + { + return regularMod; + } + } + + /// + /// Returns the natural (base e) logarithm of a specified number. + /// + /// The number to take the natural log of. + /// The natural log of + public static float Log(float x) => (float)Math.Log(x); + + /// + /// Returns the logarithm of a specified number in a specified base. + /// + /// The number to take the log of. + /// The base of the log + /// The log of with base + public static float Log(float x, float y) + { + if (float.IsNaN(x)) + { + return x; // IEEE 754-2008: NaN payload must be preserved + } + + if (float.IsNaN(y)) + { + return y; // IEEE 754-2008: NaN payload must be preserved + } + + if (y == 1) + { + return float.NaN; + } + + if ((x != 1) && ((y == 0) || float.IsPositiveInfinity(y))) + { + return float.NaN; + } + + return Log(x) / Log(y); + } + + /// + /// Returns the base 10 logarithm of a specified number. + /// + /// The number to take the base 10 log of. + /// The base 10 log of + public static float Log10(float x) => (float)Math.Log10(x); + + /// + /// Returns the larger of two single-precision floating-point numbers. + /// + /// The first number to compare. + /// The second number to compare. + /// The larger of and + public static float Max(float x, float y) => Math.Max(x, y); + + /// + /// Returns the smaller of two single-precision floating-point numbers. + /// + /// The first number to compare. + /// The second number to compare. + /// The smaller of and + public static float Min(float x, float y) => Math.Min(x, y); + + /// + /// Returns a specified number raised to the specified power. + /// + /// The base number. + /// The specified power. + /// raised to the power of + public static float Pow(float x, float y) => (float)Math.Pow(x, y); + + /// + /// Rounds a single-precision floating-point value to the nearest integral value, and rounds midpoint values to the nearest even number. + /// + /// The number to round. + /// The rounded representation of + public static float Round(float x) => (float)Math.Round(x); + + /// + /// Rounds a single-precision floating-point value to a specified number of fractional digits, and rounds midpoint values to the nearest even number. + /// + /// The number to round. + /// How many fractional digits to keep. + /// The rounded representation of with fractional digits + public static float Round(float x, int digits) => (float)Math.Round(x, digits); + + /// + /// Rounds a single-precision floating-point value to a specified number of fractional digits using the specified rounding convention. + /// + /// The number to round. + /// How many fractional digits to keep. + /// The rounding convention to use. + /// The rounded representation of with fractional digits using rounding convention + public static float Round(float x, int digits, MidpointRounding mode) => (float)Math.Round(x, digits, mode); + + /// + /// Rounds a single-precision floating-point value to an integer using the specified rounding convention. + /// + /// The number to round. + /// The rounding convention to use. + /// The rounded representation of using rounding convention + public static float Round(float x, MidpointRounding mode) => (float)Math.Round(x, mode); + + /// + /// Returns an integer that indicates the sign of a single-precision floating-point number. + /// + /// The number check the sign of. + /// The sign of + public static int Sign(float x) => Math.Sign(x); + + /// + /// Returns the sine of the specified angle. + /// + /// The angle to take the sine of. + /// The sine of + public static float Sin(float x) => (float)Math.Sin(x); + + /// + /// Returns the hyperbolic sine of the specified angle. + /// + /// The angle to take the hyperbolic sine of. + /// The hyperbolic sine of + public static float Sinh(float x) => (float)Math.Sinh(x); + + /// + /// Returns the square root of a specified number. + /// + /// The number to take the square root of. + /// The square root of + public static float Sqrt(float x) => (float)Math.Sqrt(x); + + /// + /// Returns the tangent of the specified angle. + /// + /// The angle to take the tangent of. + /// The tangent of + public static float Tan(float x) => (float)Math.Tan(x); + + /// + /// Returns the hyperbolic tangent of the specified angle. + /// + /// The angle to take the hyperbolic tangent of. + /// The hyperbolic tangent of + public static float Tanh(float x) => (float)Math.Tanh(x); + + /// + /// Calculates the integral part of a specified single-precision floating-point number. + /// + /// The number to truncate. + /// The truncated representation of + public static float Truncate(float x) => (float)Math.Truncate(x); + } +} diff --git a/src/libraries/Microsoft.Bcl.Numerics/src/System/Microsoft.Bcl.Numerics.Forwards.cs b/src/libraries/Microsoft.Bcl.Numerics/src/System/Microsoft.Bcl.Numerics.Forwards.cs new file mode 100644 index 0000000000000..641ce5525675f --- /dev/null +++ b/src/libraries/Microsoft.Bcl.Numerics/src/System/Microsoft.Bcl.Numerics.Forwards.cs @@ -0,0 +1,4 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.MathF))] diff --git a/src/libraries/Microsoft.Bcl.Numerics/tests/MathF.cs b/src/libraries/Microsoft.Bcl.Numerics/tests/MathF.cs new file mode 100644 index 0000000000000..cc615e59d433a --- /dev/null +++ b/src/libraries/Microsoft.Bcl.Numerics/tests/MathF.cs @@ -0,0 +1,1151 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +#pragma warning disable xUnit1025 // reporting duplicate test cases due to not distinguishing 0.0 from -0.0 + +namespace System.Tests +{ + public static class MathFTests + { + // binary32 (float) has a machine epsilon of 2^-23 (approx. 1.19e-07). However, this + // is slightly too accurate when writing tests meant to run against libm implementations + // for various platforms. 2^-21 (approx. 4.76e-07) seems to be as accurate as we can get. + // + // The tests themselves will take CrossPlatformMachineEpsilon and adjust it according to the expected result + // so that the delta used for comparison will compare the most significant digits and ignore + // any digits that are outside the single precision range (6-9 digits). + + // For example, a test with an expect result in the format of 0.xxxxxxxxx will use + // CrossPlatformMachineEpsilon for the variance, while an expected result in the format of 0.0xxxxxxxxx + // will use CrossPlatformMachineEpsilon / 10 and expected result in the format of x.xxxxxx will + // use CrossPlatformMachineEpsilon * 10. + private const float CrossPlatformMachineEpsilon = 4.76837158e-07f; + + // The existing estimate functions either have an error of no more than 1.5 * 2^-12 (approx. 3.66e-04) + // or perform one Newton-Raphson iteration which, for the currently tested values, gives an error of + // no more than approx. 1.5 * 2^-7 (approx 1.17e-02). + private const double CrossPlatformMachineEpsilonForEstimates = 1.171875e-02f; + + [Fact] + public static void E() + { + Assert.Equal(2.71828183f, MathF.E); + } + + [Fact] + public static void Pi() + { + Assert.Equal(3.14159265f, MathF.PI); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.PositiveInfinity, 0.0f)] + [InlineData(-3.14159265f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // value: -(pi) expected: (pi) + [InlineData(-2.71828183f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // value: -(e) expected: (e) + [InlineData(-2.30258509f, 2.30258509f, CrossPlatformMachineEpsilon * 10)] // value: -(ln(10)) expected: (ln(10)) + [InlineData(-1.57079633f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // value: -(pi / 2) expected: (pi / 2) + [InlineData(-1.44269504f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // value: -(log2(e)) expected: (log2(e)) + [InlineData(-1.41421356f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // value: -(sqrt(2)) expected: (sqrt(2)) + [InlineData(-1.12837917f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // value: -(2 / sqrt(pi)) expected: (2 / sqrt(pi)) + [InlineData(-1.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-0.785398163f, 0.785398163f, CrossPlatformMachineEpsilon)] // value: -(pi / 4) expected: (pi / 4) + [InlineData(-0.707106781f, 0.707106781f, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) expected: (1 / sqrt(2)) + [InlineData(-0.693147181f, 0.693147181f, CrossPlatformMachineEpsilon)] // value: -(ln(2)) expected: (ln(2)) + [InlineData(-0.636619772f, 0.636619772f, CrossPlatformMachineEpsilon)] // value: -(2 / pi) expected: (2 / pi) + [InlineData(-0.434294482f, 0.434294482f, CrossPlatformMachineEpsilon)] // value: -(log10(e)) expected: (log10(e)) + [InlineData(-0.318309886f, 0.318309886f, CrossPlatformMachineEpsilon)] // value: -(1 / pi) expected: (1 / pi) + [InlineData(-0.0f, 0.0f, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 0.318309886f, CrossPlatformMachineEpsilon)] // value: (1 / pi) expected: (1 / pi) + [InlineData(0.434294482f, 0.434294482f, CrossPlatformMachineEpsilon)] // value: (log10(e)) expected: (log10(e)) + [InlineData(0.636619772f, 0.636619772f, CrossPlatformMachineEpsilon)] // value: (2 / pi) expected: (2 / pi) + [InlineData(0.693147181f, 0.693147181f, CrossPlatformMachineEpsilon)] // value: (ln(2)) expected: (ln(2)) + [InlineData(0.707106781f, 0.707106781f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) expected: (1 / sqrt(2)) + [InlineData(0.785398163f, 0.785398163f, CrossPlatformMachineEpsilon)] // value: (pi / 4) expected: (pi / 4) + [InlineData(1.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.12837917f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // value: (2 / sqrt(pi)) expected: (2 / sqrt(pi)) + [InlineData(1.41421356f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // value: (sqrt(2)) expected: (sqrt(2)) + [InlineData(1.44269504f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // value: (log2(e)) expected: (log2(e)) + [InlineData(1.57079633f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2) expected: (pi / 2) + [InlineData(2.30258509f, 2.30258509f, CrossPlatformMachineEpsilon * 10)] // value: (ln(10)) expected: (ln(10)) + [InlineData(2.71828183f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // value: (e) expected: (e) + [InlineData(3.14159265f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // value: (pi) expected: (pi) + [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Abs(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Abs(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(-3.14159265f, float.NaN, 0.0f)] // value: -(pi) + [InlineData(-2.71828183f, float.NaN, 0.0f)] // value: -(e) + [InlineData(-1.41421356f, float.NaN, 0.0f)] // value: -(sqrt(2)) + [InlineData(-1.0f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi) + [InlineData(-0.911733915f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: (e) + [InlineData(-0.668201510f, 2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10)) + [InlineData(-0.0f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(0.127751218f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e)) + [InlineData(0.155943695f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2)) + [InlineData(0.428125148f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi)) + [InlineData(0.540302306f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.707106781f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4), value: (1 / sqrt(2)) + [InlineData(0.760244597f, 0.707106781f, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2)) + [InlineData(0.769238901f, 0.693147181f, CrossPlatformMachineEpsilon)] // expected: (ln(2)) + [InlineData(0.804109828f, 0.636619772f, CrossPlatformMachineEpsilon)] // expected: (2 / pi) + [InlineData(0.907167129f, 0.434294482f, CrossPlatformMachineEpsilon)] // expected: (log10(e)) + [InlineData(0.949765715f, 0.318309886f, CrossPlatformMachineEpsilon)] // expected: (1 / pi) + [InlineData(1.0f, 0.0f, 0.0f)] + [InlineData(1.41421356f, float.NaN, 0.0f)] // value: (sqrt(2)) + [InlineData(2.71828183f, float.NaN, 0.0f)] // value: (e) + [InlineData(3.14159265f, float.NaN, 0.0f)] // value: (pi) + [InlineData(float.PositiveInfinity, float.NaN, 0.0f)] + public static void Acos(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Acos(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(-3.14159265f, float.NaN, 0.0f)] // value: -(pi) + [InlineData(-2.71828183f, float.NaN, 0.0f)] // value: -(e) + [InlineData(-1.41421356f, float.NaN, 0.0f)] // value: -(sqrt(2)) + [InlineData(-1.0f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(-0.991806244f, -1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e)) + [InlineData(-0.987765946f, -1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2)) + [InlineData(-0.903719457f, -1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: -(2 / sqrt(pi)) + [InlineData(-0.841470985f, -1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-0.743980337f, -0.839007561f, CrossPlatformMachineEpsilon)] // expected: -(pi - ln(10)) + [InlineData(-0.707106781f, -0.785398163f, CrossPlatformMachineEpsilon)] // expected: -(pi / 4), value: (1 / sqrt(2)) + [InlineData(-0.649636939f, -0.707106781f, CrossPlatformMachineEpsilon)] // expected: -(1 / sqrt(2)) + [InlineData(-0.638961276f, -0.693147181f, CrossPlatformMachineEpsilon)] // expected: -(ln(2)) + [InlineData(-0.594480769f, -0.636619772f, CrossPlatformMachineEpsilon)] // expected: -(2 / pi) + [InlineData(-0.420770483f, -0.434294482f, CrossPlatformMachineEpsilon)] // expected: -(log10(e)) + [InlineData(-0.410781291f, -0.423310825f, CrossPlatformMachineEpsilon)] // expected: -(pi - e) + [InlineData(-0.312961796f, -0.318309886f, CrossPlatformMachineEpsilon)] // expected: -(1 / pi) + [InlineData(-0.0f, -0.0f, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.312961796f, 0.318309886f, CrossPlatformMachineEpsilon)] // expected: (1 / pi) + [InlineData(0.410781291f, 0.423310825f, CrossPlatformMachineEpsilon)] // expected: (pi - e) + [InlineData(0.420770483f, 0.434294482f, CrossPlatformMachineEpsilon)] // expected: (log10(e)) + [InlineData(0.594480769f, 0.636619772f, CrossPlatformMachineEpsilon)] // expected: (2 / pi) + [InlineData(0.638961276f, 0.693147181f, CrossPlatformMachineEpsilon)] // expected: (ln(2)) + [InlineData(0.649636939f, 0.707106781f, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2)) + [InlineData(0.707106781f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4), value: (1 / sqrt(2)) + [InlineData(0.743980337f, 0.839007561f, CrossPlatformMachineEpsilon)] // expected: (pi - ln(10)) + [InlineData(0.841470985f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.903719457f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi)) + [InlineData(0.987765946f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2)) + [InlineData(0.991806244f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e)) + [InlineData(1.0f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(1.41421356f, float.NaN, 0.0f)] // value: (sqrt(2)) + [InlineData(2.71828183f, float.NaN, 0.0f)] // value: (e) + [InlineData(3.14159265f, float.NaN, 0.0f)] // value: (pi) + [InlineData(float.PositiveInfinity, float.NaN, 0.0f)] + public static void Asin(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Asin(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(-7.76357567f, -1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e)) + [InlineData(-6.33411917f, -1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2)) + [InlineData(-2.11087684f, -1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: -(2 / sqrt(pi)) + [InlineData(-1.55740772f, -1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-1.11340715f, -0.839007561f, CrossPlatformMachineEpsilon)] // expected: -(pi - ln(10)) + [InlineData(-1.0f, -0.785398163f, CrossPlatformMachineEpsilon)] // expected: -(pi / 4) + [InlineData(-0.854510432f, -0.707106781f, CrossPlatformMachineEpsilon)] // expected: -(1 / sqrt(2)) + [InlineData(-0.830640878f, -0.693147181f, CrossPlatformMachineEpsilon)] // expected: -(ln(2)) + [InlineData(-0.739302950f, -0.636619772f, CrossPlatformMachineEpsilon)] // expected: -(2 / pi) + [InlineData(-0.463829067f, -0.434294482f, CrossPlatformMachineEpsilon)] // expected: -(log10(e)) + [InlineData(-0.450549534f, -0.423310825f, CrossPlatformMachineEpsilon)] // expected: -(pi - e) + [InlineData(-0.329514733f, -0.318309886f, CrossPlatformMachineEpsilon)] // expected: -(1 / pi) + [InlineData(-0.0f, -0.0f, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.329514733f, 0.318309886f, CrossPlatformMachineEpsilon)] // expected: (1 / pi) + [InlineData(0.450549534f, 0.423310825f, CrossPlatformMachineEpsilon)] // expected: (pi - e) + [InlineData(0.463829067f, 0.434294482f, CrossPlatformMachineEpsilon)] // expected: (log10(e)) + [InlineData(0.739302950f, 0.636619772f, CrossPlatformMachineEpsilon)] // expected: (2 / pi) + [InlineData(0.830640878f, 0.693147181f, CrossPlatformMachineEpsilon)] // expected: (ln(2)) + [InlineData(0.854510432f, 0.707106781f, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2)) + [InlineData(1.0f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4) + [InlineData(1.11340715f, 0.839007561f, CrossPlatformMachineEpsilon)] // expected: (pi - ln(10)) + [InlineData(1.55740772f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(2.11087684f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi)) + [InlineData(6.33411917f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2)) + [InlineData(7.76357567f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e)) + [InlineData(float.PositiveInfinity, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + public static void Atan(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Atan(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, -1.0f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(float.NegativeInfinity, -0.0f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(float.NegativeInfinity, float.NaN, float.NaN, 0.0f)] + [InlineData(float.NegativeInfinity, 0.0f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(float.NegativeInfinity, 1.0f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(-1.0f, -1.0f, -2.35619449f, CrossPlatformMachineEpsilon * 10)] // expected: -(3 * pi / 4) + [InlineData(-1.0f, -0.0f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(-1.0f, float.NaN, float.NaN, 0.0f)] + [InlineData(-1.0f, 0.0f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(-1.0f, 1.0f, -0.785398163f, CrossPlatformMachineEpsilon)] // expected: -(pi / 4) + [InlineData(-1.0f, float.PositiveInfinity, -0.0f, 0.0f)] + [InlineData(-0.991806244f, -0.127751218f, -1.69889761f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi - log2(e)) + [InlineData(-0.991806244f, 0.127751218f, -1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e)) + [InlineData(-0.987765946f, -0.155943695f, -1.72737909f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi - sqrt(2)) + [InlineData(-0.987765946f, 0.155943695f, -1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2)) + [InlineData(-0.903719457f, -0.428125148f, -2.01321349f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi - (2 / sqrt(pi)) + [InlineData(-0.903719457f, 0.428125148f, -1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: -(2 / sqrt(pi) + [InlineData(-0.841470985f, -0.540302306f, -2.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi - 1) + [InlineData(-0.841470985f, 0.540302306f, -1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-0.743980337f, -0.668201510f, -2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: -(ln(10)) + [InlineData(-0.743980337f, 0.668201510f, -0.839007561f, CrossPlatformMachineEpsilon)] // expected: -(pi - ln(10)) + [InlineData(-0.707106781f, -0.707106781f, -2.35619449f, CrossPlatformMachineEpsilon * 10)] // expected: -(3 * pi / 4), y: -(1 / sqrt(2)) x: -(1 / sqrt(2)) + [InlineData(-0.707106781f, 0.707106781f, -0.785398163f, CrossPlatformMachineEpsilon)] // expected: -(pi / 4), y: -(1 / sqrt(2)) x: (1 / sqrt(2)) + [InlineData(-0.649636939f, -0.760244597f, -2.43448587f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi - (1 / sqrt(2)) + [InlineData(-0.649636939f, 0.760244597f, -0.707106781f, CrossPlatformMachineEpsilon)] // expected: -(1 / sqrt(2)) + [InlineData(-0.638961276f, -0.769238901f, -2.44844547f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi - ln(2)) + [InlineData(-0.638961276f, 0.769238901f, -0.693147181f, CrossPlatformMachineEpsilon)] // expected: -(ln(2)) + [InlineData(-0.594480769f, -0.804109828f, -2.50497288f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi - (2 / pi)) + [InlineData(-0.594480769f, 0.804109828f, -0.636619772f, CrossPlatformMachineEpsilon)] // expected: -(2 / pi) + [InlineData(-0.420770483f, -0.907167129f, -2.70729817f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi - log10(e)) + [InlineData(-0.420770483f, 0.907167129f, -0.434294482f, CrossPlatformMachineEpsilon)] // expected: -(log10(e)) + [InlineData(-0.410781291f, -0.911733915f, -2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: -(e) + [InlineData(-0.410781291f, 0.911733915f, -0.423310825f, CrossPlatformMachineEpsilon)] // expected: -(pi - e) + [InlineData(-0.312961796f, -0.949765715f, -2.82328277f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi - (1 / pi)) + [InlineData(-0.312961796f, 0.949765715f, -0.318309886f, CrossPlatformMachineEpsilon)] // expected: -(1 / pi) + [InlineData(-0.0f, float.NegativeInfinity, -3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi) + [InlineData(-0.0f, -1.0f, -3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi) + [InlineData(-0.0f, -0.0f, -3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi) + [InlineData(-0.0f, float.NaN, float.NaN, 0.0f)] + [InlineData(-0.0f, 0.0f, -0.0f, 0.0f)] + [InlineData(-0.0f, 1.0f, -0.0f, 0.0f)] + [InlineData(-0.0f, float.PositiveInfinity, -0.0f, 0.0f)] + [InlineData(float.NaN, float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(float.NaN, -1.0f, float.NaN, 0.0f)] + [InlineData(float.NaN, -0.0f, float.NaN, 0.0f)] + [InlineData(float.NaN, float.NaN, float.NaN, 0.0f)] + [InlineData(float.NaN, 0.0f, float.NaN, 0.0f)] + [InlineData(float.NaN, 1.0f, float.NaN, 0.0f)] + [InlineData(float.NaN, float.PositiveInfinity, float.NaN, 0.0f)] + [InlineData(0.0f, float.NegativeInfinity, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi) + [InlineData(0.0f, -1.0f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi) + [InlineData(0.0f, -0.0f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi) + [InlineData(0.0f, float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f, 0.0f)] + [InlineData(0.0f, 1.0f, 0.0f, 0.0f)] + [InlineData(0.0f, float.PositiveInfinity, 0.0f, 0.0f)] + [InlineData(0.312961796f, -0.949765715f, 2.82328277f, CrossPlatformMachineEpsilon * 10)] // expected: (pi - (1 / pi)) + [InlineData(0.312961796f, 0.949765715f, 0.318309886f, CrossPlatformMachineEpsilon)] // expected: (1 / pi) + [InlineData(0.410781291f, -0.911733915f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: (e) + [InlineData(0.410781291f, 0.911733915f, 0.423310825f, CrossPlatformMachineEpsilon)] // expected: (pi - e) + [InlineData(0.420770483f, -0.907167129f, 2.70729817f, CrossPlatformMachineEpsilon * 10)] // expected: (pi - log10(e)) + [InlineData(0.420770483f, 0.907167129f, 0.434294482f, CrossPlatformMachineEpsilon)] // expected: (log10(e)) + [InlineData(0.594480769f, -0.804109828f, 2.50497288f, CrossPlatformMachineEpsilon * 10)] // expected: (pi - (2 / pi)) + [InlineData(0.594480769f, 0.804109828f, 0.636619772f, CrossPlatformMachineEpsilon)] // expected: (2 / pi) + [InlineData(0.638961276f, -0.769238901f, 2.44844547f, CrossPlatformMachineEpsilon * 10)] // expected: (pi - ln(2)) + [InlineData(0.638961276f, 0.769238901f, 0.693147181f, CrossPlatformMachineEpsilon)] // expected: (ln(2)) + [InlineData(0.649636939f, -0.760244597f, 2.43448587f, CrossPlatformMachineEpsilon * 10)] // expected: (pi - (1 / sqrt(2)) + [InlineData(0.649636939f, 0.760244597f, 0.707106781f, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2)) + [InlineData(0.707106781f, -0.707106781f, 2.35619449f, CrossPlatformMachineEpsilon * 10)] // expected: (3 * pi / 4), y: (1 / sqrt(2)) x: -(1 / sqrt(2)) + [InlineData(0.707106781f, 0.707106781f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4), y: (1 / sqrt(2)) x: (1 / sqrt(2)) + [InlineData(0.743980337f, -0.668201510f, 2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10)) + [InlineData(0.743980337f, 0.668201510f, 0.839007561f, CrossPlatformMachineEpsilon)] // expected: (pi - ln(10)) + [InlineData(0.841470985f, -0.540302306f, 2.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi - 1) + [InlineData(0.841470985f, 0.540302306f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.903719457f, -0.428125148f, 2.01321349f, CrossPlatformMachineEpsilon * 10)] // expected: (pi - (2 / sqrt(pi)) + [InlineData(0.903719457f, 0.428125148f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi)) + [InlineData(0.987765946f, -0.155943695f, 1.72737909f, CrossPlatformMachineEpsilon * 10)] // expected: (pi - sqrt(2)) + [InlineData(0.987765946f, 0.155943695f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2)) + [InlineData(0.991806244f, -0.127751218f, 1.69889761f, CrossPlatformMachineEpsilon * 10)] // expected: (pi - log2(e)) + [InlineData(0.991806244f, 0.127751218f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e)) + [InlineData(1.0f, -1.0f, 2.35619449f, CrossPlatformMachineEpsilon * 10)] // expected: (3 * pi / 4) + [InlineData(1.0f, -0.0f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(1.0f, float.NaN, float.NaN, 0.0f)] + [InlineData(1.0f, 0.0f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(1.0f, 1.0f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4) + [InlineData(1.0f, float.PositiveInfinity, 0.0f, 0.0f)] + [InlineData(float.PositiveInfinity, -1.0f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(float.PositiveInfinity, -0.0f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(float.PositiveInfinity, float.NaN, float.NaN, 0.0f)] + [InlineData(float.PositiveInfinity, 0.0f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(float.PositiveInfinity, 1.0f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + public static void Atan2(float y, float x, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Atan2(y, x), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NegativeInfinity, 0.0f)] + [InlineData(-3.14159265f, -3.0f, 0.0f)] // value: -(pi) + [InlineData(-2.71828183f, -2.0f, 0.0f)] // value: -(e) + [InlineData(-2.30258509f, -2.0f, 0.0f)] // value: -(ln(10)) + [InlineData(-1.57079633f, -1.0f, 0.0f)] // value: -(pi / 2) + [InlineData(-1.44269504f, -1.0f, 0.0f)] // value: -(log2(e)) + [InlineData(-1.41421356f, -1.0f, 0.0f)] // value: -(sqrt(2)) + [InlineData(-1.12837917f, -1.0f, 0.0f)] // value: -(2 / sqrt(pi)) + [InlineData(-1.0f, -1.0f, 0.0f)] + [InlineData(-0.785398163f, 0.0f, 0.0f)] // value: (pi / 4) + [InlineData(-0.707106781f, 0.0f, 0.0f)] // value: (1 / sqrt(2)) + [InlineData(-0.693147181f, 0.0f, 0.0f)] // value: (ln(2)) + [InlineData(-0.636619772f, 0.0f, 0.0f)] // value: (2 / pi) + [InlineData(-0.434294482f, 0.0f, 0.0f)] // value: (log10(e)) + [InlineData(-0.318309886f, 0.0f, 0.0f)] // value: (1 / pi) + [InlineData(-0.0f, -0.0f, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 1.0f, 0.0f)] // value: (1 / pi) + [InlineData(0.434294482f, 1.0f, 0.0f)] // value: (log10(e)) + [InlineData(0.636619772f, 1.0f, 0.0f)] // value: (2 / pi) + [InlineData(0.693147181f, 1.0f, 0.0f)] // value: (ln(2)) + [InlineData(0.707106781f, 1.0f, 0.0f)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 1.0f, 0.0f)] // value: (pi / 4) + [InlineData(1.0f, 1.0f, 0.0f)] + [InlineData(1.12837917f, 2.0f, 0.0f)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 2.0f, 0.0f)] // value: (sqrt(2)) + [InlineData(1.44269504f, 2.0f, 0.0f)] // value: (log2(e)) + [InlineData(1.57079633f, 2.0f, 0.0f)] // value: (pi / 2) + [InlineData(2.30258509f, 3.0f, 0.0f)] // value: (ln(10)) + [InlineData(2.71828183f, 3.0f, 0.0f)] // value: (e) + [InlineData(3.14159265f, 4.0f, 0.0f)] // value: (pi) + [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Ceiling(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Ceiling(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(-3.14159265f, -1.0f, CrossPlatformMachineEpsilon * 10)] // value: -(pi) + [InlineData(-2.71828183f, -0.911733918f, CrossPlatformMachineEpsilon)] // value: -(e) + [InlineData(-2.30258509f, -0.668201510f, CrossPlatformMachineEpsilon)] // value: -(ln(10)) + [InlineData(-1.57079633f, 0.0f, CrossPlatformMachineEpsilon)] // value: -(pi / 2) + [InlineData(-1.44269504f, 0.127751218f, CrossPlatformMachineEpsilon)] // value: -(log2(e)) + [InlineData(-1.41421356f, 0.155943695f, CrossPlatformMachineEpsilon)] // value: -(sqrt(2)) + [InlineData(-1.12837917f, 0.428125148f, CrossPlatformMachineEpsilon)] // value: -(2 / sqrt(pi)) + [InlineData(-1.0f, 0.540302306f, CrossPlatformMachineEpsilon)] + [InlineData(-0.785398163f, 0.707106781f, CrossPlatformMachineEpsilon)] // value: -(pi / 4), expected: (1 / sqrt(2)) + [InlineData(-0.707106781f, 0.760244597f, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) + [InlineData(-0.693147181f, 0.769238901f, CrossPlatformMachineEpsilon)] // value: -(ln(2)) + [InlineData(-0.636619772f, 0.804109828f, CrossPlatformMachineEpsilon)] // value: -(2 / pi) + [InlineData(-0.434294482f, 0.907167129f, CrossPlatformMachineEpsilon)] // value: -(log10(e)) + [InlineData(-0.318309886f, 0.949765715f, CrossPlatformMachineEpsilon)] // value: -(1 / pi) + [InlineData(-0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.318309886f, 0.949765715f, CrossPlatformMachineEpsilon)] // value: (1 / pi) + [InlineData(0.434294482f, 0.907167129f, CrossPlatformMachineEpsilon)] // value: (log10(e)) + [InlineData(0.636619772f, 0.804109828f, CrossPlatformMachineEpsilon)] // value: (2 / pi) + [InlineData(0.693147181f, 0.769238901f, CrossPlatformMachineEpsilon)] // value: (ln(2)) + [InlineData(0.707106781f, 0.760244597f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 0.707106781f, CrossPlatformMachineEpsilon)] // value: (pi / 4), expected: (1 / sqrt(2)) + [InlineData(1.0f, 0.540302306f, CrossPlatformMachineEpsilon)] + [InlineData(1.12837917f, 0.428125148f, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 0.155943695f, CrossPlatformMachineEpsilon)] // value: (sqrt(2)) + [InlineData(1.44269504f, 0.127751218f, CrossPlatformMachineEpsilon)] // value: (log2(e)) + [InlineData(1.57079633f, 0.0f, CrossPlatformMachineEpsilon)] // value: (pi / 2) + [InlineData(2.30258509f, -0.668201510f, CrossPlatformMachineEpsilon)] // value: (ln(10)) + [InlineData(2.71828183f, -0.911733918f, CrossPlatformMachineEpsilon)] // value: (e) + [InlineData(3.14159265f, -1.0f, CrossPlatformMachineEpsilon * 10)] // value: (pi) + [InlineData(float.PositiveInfinity, float.NaN, 0.0f)] + public static void Cos(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Cos(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.PositiveInfinity, 0.0f)] + [InlineData(-3.14159265f, 11.5919533f, CrossPlatformMachineEpsilon * 100)] // value: (pi) + [InlineData(-2.71828183f, 7.61012514f, CrossPlatformMachineEpsilon * 10)] // value: (e) + [InlineData(-2.30258509f, 5.05f, CrossPlatformMachineEpsilon * 10)] // value: (ln(10)) + [InlineData(-1.57079633f, 2.50917848f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2) + [InlineData(-1.44269504f, 2.23418810f, CrossPlatformMachineEpsilon * 10)] // value: (log2(e)) + [InlineData(-1.41421356f, 2.17818356f, CrossPlatformMachineEpsilon * 10)] // value: (sqrt(2)) + [InlineData(-1.12837917f, 1.70710014f, CrossPlatformMachineEpsilon * 10)] // value: (2 / sqrt(pi)) + [InlineData(-1.0f, 1.54308063f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-0.785398163f, 1.32460909f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 4) + [InlineData(-0.707106781f, 1.26059184f, CrossPlatformMachineEpsilon * 10)] // value: (1 / sqrt(2)) + [InlineData(-0.693147181f, 1.25f, CrossPlatformMachineEpsilon * 10)] // value: (ln(2)) + [InlineData(-0.636619772f, 1.20957949f, CrossPlatformMachineEpsilon * 10)] // value: (2 / pi) + [InlineData(-0.434294482f, 1.09579746f, CrossPlatformMachineEpsilon * 10)] // value: (log10(e)) + [InlineData(-0.318309886f, 1.05108979f, CrossPlatformMachineEpsilon * 10)] // value: (1 / pi) + [InlineData(-0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.318309886f, 1.05108979f, CrossPlatformMachineEpsilon * 10)] // value: (1 / pi) + [InlineData(0.434294482f, 1.09579746f, CrossPlatformMachineEpsilon * 10)] // value: (log10(e)) + [InlineData(0.636619772f, 1.20957949f, CrossPlatformMachineEpsilon * 10)] // value: (2 / pi) + [InlineData(0.693147181f, 1.25f, CrossPlatformMachineEpsilon * 10)] // value: (ln(2)) + [InlineData(0.707106781f, 1.26059184f, CrossPlatformMachineEpsilon * 10)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 1.32460909f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 4) + [InlineData(1.0f, 1.54308063f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.12837917f, 1.70710014f, CrossPlatformMachineEpsilon * 10)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 2.17818356f, CrossPlatformMachineEpsilon * 10)] // value: (sqrt(2)) + [InlineData(1.44269504f, 2.23418810f, CrossPlatformMachineEpsilon * 10)] // value: (log2(e)) + [InlineData(1.57079633f, 2.50917848f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2) + [InlineData(2.30258509f, 5.05f, CrossPlatformMachineEpsilon * 10)] // value: (ln(10)) + [InlineData(2.71828183f, 7.61012514f, CrossPlatformMachineEpsilon * 10)] // value: (e) + [InlineData(3.14159265f, 11.5919533f, CrossPlatformMachineEpsilon * 100)] // value: (pi) + [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Cosh(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Cosh(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, 0.0f, CrossPlatformMachineEpsilon)] + [InlineData(-3.14159265f, 0.0432139183f, CrossPlatformMachineEpsilon / 10)] // value: -(pi) + [InlineData(-2.71828183f, 0.0659880358f, CrossPlatformMachineEpsilon / 10)] // value: -(e) + [InlineData(-2.30258509f, 0.1f, CrossPlatformMachineEpsilon)] // value: -(ln(10)) + [InlineData(-1.57079633f, 0.207879576f, CrossPlatformMachineEpsilon)] // value: -(pi / 2) + [InlineData(-1.44269504f, 0.236290088f, CrossPlatformMachineEpsilon)] // value: -(log2(e)) + [InlineData(-1.41421356f, 0.243116734f, CrossPlatformMachineEpsilon)] // value: -(sqrt(2)) + [InlineData(-1.12837917f, 0.323557264f, CrossPlatformMachineEpsilon)] // value: -(2 / sqrt(pi)) + [InlineData(-1.0f, 0.367879441f, CrossPlatformMachineEpsilon)] + [InlineData(-0.785398163f, 0.455938128f, CrossPlatformMachineEpsilon)] // value: -(pi / 4) + [InlineData(-0.707106781f, 0.493068691f, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) + [InlineData(-0.693147181f, 0.5f, CrossPlatformMachineEpsilon)] // value: -(ln(2)) + [InlineData(-0.636619772f, 0.529077808f, CrossPlatformMachineEpsilon)] // value: -(2 / pi) + [InlineData(-0.434294482f, 0.647721485f, CrossPlatformMachineEpsilon)] // value: -(log10(e)) + [InlineData(-0.318309886f, 0.727377349f, CrossPlatformMachineEpsilon)] // value: -(1 / pi) + [InlineData(-0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.318309886f, 1.37480223f, CrossPlatformMachineEpsilon * 10)] // value: (1 / pi) + [InlineData(0.434294482f, 1.54387344f, CrossPlatformMachineEpsilon * 10)] // value: (log10(e)) + [InlineData(0.636619772f, 1.89008116f, CrossPlatformMachineEpsilon * 10)] // value: (2 / pi) + [InlineData(0.693147181f, 2.0f, CrossPlatformMachineEpsilon * 10)] // value: (ln(2)) + [InlineData(0.707106781f, 2.02811498f, CrossPlatformMachineEpsilon * 10)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 2.19328005f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 4) + [InlineData(1.0f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: (e) + [InlineData(1.12837917f, 3.09064302f, CrossPlatformMachineEpsilon * 10)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 4.11325038f, CrossPlatformMachineEpsilon * 10)] // value: (sqrt(2)) + [InlineData(1.44269504f, 4.23208611f, CrossPlatformMachineEpsilon * 10)] // value: (log2(e)) + [InlineData(1.57079633f, 4.81047738f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2) + [InlineData(2.30258509f, 10.0f, CrossPlatformMachineEpsilon * 100)] // value: (ln(10)) + [InlineData(2.71828183f, 15.1542622f, CrossPlatformMachineEpsilon * 100)] // value: (e) + [InlineData(3.14159265f, 23.1406926f, CrossPlatformMachineEpsilon * 100)] // value: (pi) + [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Exp(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Exp(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NegativeInfinity, 0.0f)] + [InlineData(-3.14159265f, -4.0f, 0.0f)] // value: -(pi) + [InlineData(-2.71828183f, -3.0f, 0.0f)] // value: -(e) + [InlineData(-2.30258509f, -3.0f, 0.0f)] // value: -(ln(10)) + [InlineData(-1.57079633f, -2.0f, 0.0f)] // value: -(pi / 2) + [InlineData(-1.44269504f, -2.0f, 0.0f)] // value: -(log2(e)) + [InlineData(-1.41421356f, -2.0f, 0.0f)] // value: -(sqrt(2)) + [InlineData(-1.12837917f, -2.0f, 0.0f)] // value: -(2 / sqrt(pi)) + [InlineData(-1.0f, -1.0f, 0.0f)] + [InlineData(-0.785398163f, -1.0f, 0.0f)] // value: -(pi / 4) + [InlineData(-0.707106781f, -1.0f, 0.0f)] // value: -(1 / sqrt(2)) + [InlineData(-0.693147181f, -1.0f, 0.0f)] // value: -(ln(2)) + [InlineData(-0.636619772f, -1.0f, 0.0f)] // value: -(2 / pi) + [InlineData(-0.434294482f, -1.0f, 0.0f)] // value: -(log10(e)) + [InlineData(-0.318309886f, -1.0f, 0.0f)] // value: -(1 / pi) + [InlineData(-0.0f, -0.0f, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 0.0f, 0.0f)] // value: (1 / pi) + [InlineData(0.434294482f, 0.0f, 0.0f)] // value: (log10(e)) + [InlineData(0.636619772f, 0.0f, 0.0f)] // value: (2 / pi) + [InlineData(0.693147181f, 0.0f, 0.0f)] // value: (ln(2)) + [InlineData(0.707106781f, 0.0f, 0.0f)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 0.0f, 0.0f)] // value: (pi / 4) + [InlineData(1.0f, 1.0f, 0.0f)] + [InlineData(1.12837917f, 1.0f, 0.0f)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 1.0f, 0.0f)] // value: (sqrt(2)) + [InlineData(1.44269504f, 1.0f, 0.0f)] // value: (log2(e)) + [InlineData(1.57079633f, 1.0f, 0.0f)] // value: (pi / 2) + [InlineData(2.30258509f, 2.0f, 0.0f)] // value: (ln(10)) + [InlineData(2.71828183f, 2.0f, 0.0f)] // value: (e) + [InlineData(3.14159265f, 3.0f, 0.0f)] // value: (pi) + [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Floor(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Floor(value), allowedVariance); + } + + [Fact] + public static void IEEERemainder() + { + Assert.Equal(-1.0f, MathF.IEEERemainder(3.0f, 2.0f)); + Assert.Equal(0.0f, MathF.IEEERemainder(4.0f, 2.0f)); + Assert.Equal(1.0f, MathF.IEEERemainder(10.0f, 3.0f)); + Assert.Equal(-1.0f, MathF.IEEERemainder(11.0f, 3.0f)); + Assert.Equal(-2.0f, MathF.IEEERemainder(28.0f, 5.0f)); + AssertExtensions.Equal(1.8f, MathF.IEEERemainder(17.8f, 4.0f), CrossPlatformMachineEpsilon * 10); + AssertExtensions.Equal(1.4f, MathF.IEEERemainder(17.8f, 4.1f), CrossPlatformMachineEpsilon * 10); + AssertExtensions.Equal(0.1000004f, MathF.IEEERemainder(-16.3f, 4.1f), CrossPlatformMachineEpsilon / 10); + AssertExtensions.Equal(1.4f, MathF.IEEERemainder(17.8f, -4.1f), CrossPlatformMachineEpsilon * 10); + AssertExtensions.Equal(-1.4f, MathF.IEEERemainder(-17.8f, -4.1f), CrossPlatformMachineEpsilon * 10); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(-3.14159265f, float.NaN, 0.0f)] // value: -(pi) + [InlineData(-2.71828183f, float.NaN, 0.0f)] // value: -(e) + [InlineData(-1.41421356f, float.NaN, 0.0f)] // value: -(sqrt(2)) + [InlineData(-1.0f, float.NaN, 0.0f)] + [InlineData(-0.693147181f, float.NaN, 0.0f)] // value: -(ln(2)) + [InlineData(-0.434294482f, float.NaN, 0.0f)] // value: -(log10(e)) + [InlineData(-0.0f, float.NegativeInfinity, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, float.NegativeInfinity, 0.0f)] + [InlineData(0.0432139183f, -3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi) + [InlineData(0.0659880358f, -2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: -(e) + [InlineData(0.1f, -2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: -(ln(10)) + [InlineData(0.207879576f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(0.236290088f, -1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e)) + [InlineData(0.243116734f, -1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2)) + [InlineData(0.323557264f, -1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: -(2 / sqrt(pi)) + [InlineData(0.367879441f, -1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.455938128f, -0.785398163f, CrossPlatformMachineEpsilon)] // expected: -(pi / 4) + [InlineData(0.493068691f, -0.707106781f, CrossPlatformMachineEpsilon)] // expected: -(1 / sqrt(2)) + [InlineData(0.5f, -0.693147181f, CrossPlatformMachineEpsilon)] // expected: -(ln(2)) + [InlineData(0.529077808f, -0.636619772f, CrossPlatformMachineEpsilon)] // expected: -(2 / pi) + [InlineData(0.647721485f, -0.434294482f, CrossPlatformMachineEpsilon)] // expected: -(log10(e)) + [InlineData(0.727377349f, -0.318309886f, CrossPlatformMachineEpsilon)] // expected: -(1 / pi) + [InlineData(1.0f, 0.0f, 0.0f)] + [InlineData(1.37480223f, 0.318309886f, CrossPlatformMachineEpsilon)] // expected: (1 / pi) + [InlineData(1.54387344f, 0.434294482f, CrossPlatformMachineEpsilon)] // expected: (log10(e)) + [InlineData(1.89008116f, 0.636619772f, CrossPlatformMachineEpsilon)] // expected: (2 / pi) + [InlineData(2.0f, 0.693147181f, CrossPlatformMachineEpsilon)] // expected: (ln(2)) + [InlineData(2.02811498f, 0.707106781f, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2)) + [InlineData(2.19328005f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4) + [InlineData(2.71828183f, 1.0f, CrossPlatformMachineEpsilon * 10)] // value: (e) + [InlineData(3.09064302f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi)) + [InlineData(4.11325038f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2)) + [InlineData(4.23208611f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e)) + [InlineData(4.81047738f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(10.0f, 2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10)) + [InlineData(15.1542622f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: (e) + [InlineData(23.1406926f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi) + [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Log(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Log(value), allowedVariance); + } + + [Fact] + public static void LogWithBase() + { + Assert.Equal(1.0f, MathF.Log(3.0f, 3.0f)); + AssertExtensions.Equal(2.40217350f, MathF.Log(14.0f, 3.0f), CrossPlatformMachineEpsilon * 10); + Assert.Equal(float.NegativeInfinity, MathF.Log(0.0f, 3.0f)); + Assert.Equal(float.NaN, MathF.Log(-3.0f, 3.0f)); + Assert.Equal(float.NaN, MathF.Log(float.NaN, 3.0f)); + Assert.Equal(float.PositiveInfinity, MathF.Log(float.PositiveInfinity, 3.0f)); + Assert.Equal(float.NaN, MathF.Log(float.NegativeInfinity, 3.0f)); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(-3.14159265f, float.NaN, 0.0f)] // value: -(pi) + [InlineData(-2.71828183f, float.NaN, 0.0f)] // value: -(e) + [InlineData(-1.41421356f, float.NaN, 0.0f)] // value: -(sqrt(2)) + [InlineData(-1.0f, float.NaN, 0.0f)] + [InlineData(-0.693147181f, float.NaN, 0.0f)] // value: -(ln(2)) + [InlineData(-0.434294482f, float.NaN, 0.0f)] // value: -(log10(e)) + [InlineData(-0.0f, float.NegativeInfinity, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, float.NegativeInfinity, 0.0f)] + [InlineData(0.000721784159f, -3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi) + [InlineData(0.00191301410f, -2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: -(e) + [InlineData(0.00498212830f, -2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: -(ln(10)) + [InlineData(0.0268660410f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(0.0360831928f, -1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e)) + [InlineData(0.0385288847f, -1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2)) + [InlineData(0.0744082059f, -1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: -(2 / sqrt(pi)) + [InlineData(0.1f, -1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.163908636f, -0.785398163f, CrossPlatformMachineEpsilon)] // expected: -(pi / 4) + [InlineData(0.196287760f, -0.707106781f, CrossPlatformMachineEpsilon)] // expected: -(1 / sqrt(2)) + [InlineData(0.202699566f, -0.693147181f, CrossPlatformMachineEpsilon)] // expected: -(ln(2)) + [InlineData(0.230876765f, -0.636619772f, CrossPlatformMachineEpsilon)] // expected: -(2 / pi) + [InlineData(0.367879441f, -0.434294482f, CrossPlatformMachineEpsilon)] // expected: -(log10(e)) + [InlineData(0.480496373f, -0.318309886f, CrossPlatformMachineEpsilon)] // expected: -(1 / pi) + [InlineData(1.0f, 0.0f, 0.0f)] + [InlineData(2.08118116f, 0.318309886f, CrossPlatformMachineEpsilon)] // expected: (1 / pi) + [InlineData(2.71828183f, 0.434294482f, CrossPlatformMachineEpsilon)] // expected: (log10(e)) value: (e) + [InlineData(4.33131503f, 0.636619772f, CrossPlatformMachineEpsilon)] // expected: (2 / pi) + [InlineData(4.93340967f, 0.693147181f, CrossPlatformMachineEpsilon)] // expected: (ln(2)) + [InlineData(5.09456117f, 0.707106781f, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2)) + [InlineData(6.10095980f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4) + [InlineData(10.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(13.4393779f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi)) + [InlineData(25.9545535f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2)) + [InlineData(27.7137338f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e)) + [InlineData(37.2217105f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(200.717432f, 2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10)) + [InlineData(522.735300f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: (e) + [InlineData(1385.45573f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi) + [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Log10(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Log10(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity)] + [InlineData(float.PositiveInfinity, float.NegativeInfinity, float.PositiveInfinity)] + [InlineData(float.MinValue, float.MaxValue, float.MaxValue)] + [InlineData(float.MaxValue, float.MinValue, float.MaxValue)] + [InlineData(float.NaN, float.NaN, float.NaN)] + [InlineData(float.NaN, 1.0f, float.NaN)] + [InlineData(1.0f, float.NaN, float.NaN)] + [InlineData(float.PositiveInfinity, float.NaN, float.NaN)] + [InlineData(float.NegativeInfinity, float.NaN, float.NaN)] + [InlineData(float.NaN, float.PositiveInfinity, float.NaN)] + [InlineData(float.NaN, float.NegativeInfinity, float.NaN)] + [InlineData(-0.0f, 0.0f, 0.0f)] + [InlineData(0.0f, -0.0f, -0.0f)] + [InlineData(2.0f, -3.0f, 2.0f)] + [InlineData(-3.0f, 2.0f, 2.0f)] + [InlineData(3.0f, -2.0f, 3.0f)] + [InlineData(-2.0f, 3.0f, 3.0f)] + public static void Max(float x, float y, float expectedResult) + { + AssertExtensions.Equal(expectedResult, MathF.Max(x, y), 0.0f); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.NegativeInfinity)] + [InlineData(float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity)] + [InlineData(float.MinValue, float.MaxValue, float.MinValue)] + [InlineData(float.MaxValue, float.MinValue, float.MinValue)] + [InlineData(float.NaN, float.NaN, float.NaN)] + [InlineData(float.NaN, 1.0f, float.NaN)] + [InlineData(1.0f, float.NaN, float.NaN)] + [InlineData(float.PositiveInfinity, float.NaN, float.NaN)] + [InlineData(float.NegativeInfinity, float.NaN, float.NaN)] + [InlineData(float.NaN, float.PositiveInfinity, float.NaN)] + [InlineData(float.NaN, float.NegativeInfinity, float.NaN)] + [InlineData(-0.0f, 0.0f, 0.0f)] + [InlineData(0.0f, -0.0f, -0.0f)] + [InlineData(2.0f, -3.0f, -3.0f)] + [InlineData(-3.0f, 2.0f, -3.0f)] + [InlineData(3.0f, -2.0f, -2.0f)] + [InlineData(-2.0f, 3.0f, -2.0f)] + public static void Min(float x, float y, float expectedResult) + { + AssertExtensions.Equal(expectedResult, MathF.Min(x, y), 0.0f); + } + + + [Theory] + [InlineData(float.NegativeInfinity, float.NegativeInfinity, 0.0f, 0.0f)] + [InlineData(float.NegativeInfinity, -1.0f, -0.0f, 0.0f)] + [InlineData(float.NegativeInfinity, -0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(float.NegativeInfinity, float.NaN, float.NaN, 0.0f)] + [InlineData(float.NegativeInfinity, 0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(float.NegativeInfinity, 1.0f, float.NegativeInfinity, 0.0f)] + [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + [InlineData(-10.0f, float.NegativeInfinity, 0.0f, 0.0f)] + [InlineData(-10.0f, -1.57079633f, float.NaN, 0.0f)] // y: -(pi / 2) + [InlineData(-10.0f, -1.0f, -0.1f, CrossPlatformMachineEpsilon)] + [InlineData(-10.0f, -0.785398163f, float.NaN, 0.0f)] // y: -(pi / 4) + [InlineData(-10.0f, -0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-10.0f, float.NaN, float.NaN, 0.0f)] + [InlineData(-10.0f, 0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-10.0f, 0.785398163f, float.NaN, 0.0f)] // y: (pi / 4) + [InlineData(-10.0f, 1.0f, -10.0f, CrossPlatformMachineEpsilon * 100)] + [InlineData(-10.0f, 1.57079633f, float.NaN, 0.0f)] // y: (pi / 2) + [InlineData(-10.0f, float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + [InlineData(-2.71828183f, float.NegativeInfinity, 0.0f, 0.0f)] // x: -(e) + [InlineData(-2.71828183f, -1.57079633f, float.NaN, 0.0f)] // x: -(e) y: -(pi / 2) + [InlineData(-2.71828183f, -1.0f, -0.367879441f, CrossPlatformMachineEpsilon)] // x: -(e) + [InlineData(-2.71828183f, -0.785398163f, float.NaN, 0.0f)] // x: -(e) y: -(pi / 4) + [InlineData(-2.71828183f, -0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] // x: -(e) + [InlineData(-2.71828183f, float.NaN, float.NaN, 0.0f)] + [InlineData(-2.71828183f, 0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] // x: -(e) + [InlineData(-2.71828183f, 0.785398163f, float.NaN, 0.0f)] // x: -(e) y: (pi / 4) + [InlineData(-2.71828183f, 1.0f, -2.71828183f, CrossPlatformMachineEpsilon * 10)] // x: -(e) expected: (e) + [InlineData(-2.71828183f, 1.57079633f, float.NaN, 0.0f)] // x: -(e) y: (pi / 2) + [InlineData(-2.71828183f, float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + [InlineData(-1.0f, -1.0f, -1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-1.0f, -0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-1.0f, float.NaN, float.NaN, 0.0f)] + [InlineData(-1.0f, 0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-1.0f, 1.0f, -1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-0.0f, float.NegativeInfinity, float.PositiveInfinity, 0.0f)] + [InlineData(-0.0f, -3.0f, float.NegativeInfinity, 0.0f)] + [InlineData(-0.0f, -2.0f, float.PositiveInfinity, 0.0f)] + [InlineData(-0.0f, -1.57079633f, float.PositiveInfinity, 0.0f)] // y: -(pi / 2) + [InlineData(-0.0f, -1.0f, float.NegativeInfinity, 0.0f)] + [InlineData(-0.0f, -0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-0.0f, float.NaN, float.NaN, 0.0f)] + [InlineData(-0.0f, 0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-0.0f, 1.0f, -0.0f, 0.0f)] + [InlineData(-0.0f, 1.57079633f, 0.0f, 0.0f)] // y: -(pi / 2) + [InlineData(-0.0f, 2.0f, 0.0f, 0.0f)] + [InlineData(-0.0f, 3.0f, -0.0f, 0.0f)] + [InlineData(-0.0f, float.PositiveInfinity, 0.0f, 0.0f)] + [InlineData(float.NaN, float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(float.NaN, -1.0f, float.NaN, 0.0f)] + [InlineData(float.NaN, float.NaN, float.NaN, 0.0f)] + [InlineData(float.NaN, 1.0f, float.NaN, 0.0f)] + [InlineData(float.NaN, float.PositiveInfinity, float.NaN, 0.0f)] + [InlineData(0.0f, float.NegativeInfinity, float.PositiveInfinity, 0.0f)] + [InlineData(0.0f, -3.0f, float.PositiveInfinity, 0.0f)] + [InlineData(0.0f, -2.0f, float.PositiveInfinity, 0.0f)] + [InlineData(0.0f, -1.57079633f, float.PositiveInfinity, 0.0f)] // y: -(pi / 2) + [InlineData(0.0f, -1.0f, float.PositiveInfinity, 0.0f)] + [InlineData(0.0f, -0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.0f, float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.0f, 1.0f, 0.0f, 0.0f)] + [InlineData(0.0f, 1.57079633f, 0.0f, 0.0f)] // y: -(pi / 2) + [InlineData(0.0f, 2.0f, 0.0f, 0.0f)] + [InlineData(0.0f, 3.0f, 0.0f, 0.0f)] + [InlineData(0.0f, float.PositiveInfinity, 0.0f, 0.0f)] + [InlineData(1.0f, float.NegativeInfinity, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.0f, -1.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.0f, -0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.0f, 0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.0f, 1.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.0f, float.PositiveInfinity, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(2.71828183f, float.NegativeInfinity, 0.0f, 0.0f)] + [InlineData(2.71828183f, -3.14159265f, 0.0432139183f, CrossPlatformMachineEpsilon / 10)] // x: (e) y: -(pi) + [InlineData(2.71828183f, -2.71828183f, 0.0659880358f, CrossPlatformMachineEpsilon / 10)] // x: (e) y: -(e) + [InlineData(2.71828183f, -2.30258509f, 0.1f, CrossPlatformMachineEpsilon)] // x: (e) y: -(ln(10)) + [InlineData(2.71828183f, -1.57079633f, 0.207879576f, CrossPlatformMachineEpsilon)] // x: (e) y: -(pi / 2) + [InlineData(2.71828183f, -1.44269504f, 0.236290088f, CrossPlatformMachineEpsilon)] // x: (e) y: -(log2(e)) + [InlineData(2.71828183f, -1.41421356f, 0.243116734f, CrossPlatformMachineEpsilon)] // x: (e) y: -(sqrt(2)) + [InlineData(2.71828183f, -1.12837917f, 0.323557264f, CrossPlatformMachineEpsilon)] // x: (e) y: -(2 / sqrt(pi)) + [InlineData(2.71828183f, -1.0f, 0.367879441f, CrossPlatformMachineEpsilon)] // x: (e) + [InlineData(2.71828183f, -0.785398163f, 0.455938128f, CrossPlatformMachineEpsilon)] // x: (e) y: -(pi / 4) + [InlineData(2.71828183f, -0.707106781f, 0.493068691f, CrossPlatformMachineEpsilon)] // x: (e) y: -(1 / sqrt(2)) + [InlineData(2.71828183f, -0.693147181f, 0.5f, CrossPlatformMachineEpsilon)] // x: (e) y: -(ln(2)) + [InlineData(2.71828183f, -0.636619772f, 0.529077808f, CrossPlatformMachineEpsilon)] // x: (e) y: -(2 / pi) + [InlineData(2.71828183f, -0.434294482f, 0.647721485f, CrossPlatformMachineEpsilon)] // x: (e) y: -(log10(e)) + [InlineData(2.71828183f, -0.318309886f, 0.727377349f, CrossPlatformMachineEpsilon)] // x: (e) y: -(1 / pi) + [InlineData(2.71828183f, -0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] // x: (e) + [InlineData(2.71828183f, float.NaN, float.NaN, 0.0f)] + [InlineData(2.71828183f, 0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] // x: (e) + [InlineData(2.71828183f, 0.318309886f, 1.37480223f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (1 / pi) + [InlineData(2.71828183f, 0.434294482f, 1.54387344f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (log10(e)) + [InlineData(2.71828183f, 0.636619772f, 1.89008116f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (2 / pi) + [InlineData(2.71828183f, 0.693147181f, 2.0f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (ln(2)) + [InlineData(2.71828183f, 0.707106781f, 2.02811498f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (1 / sqrt(2)) + [InlineData(2.71828183f, 0.785398163f, 2.19328005f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (pi / 4) + [InlineData(2.71828183f, 1.0f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // x: (e) expected: (e) + [InlineData(2.71828183f, 1.12837917f, 3.09064302f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (2 / sqrt(pi)) + [InlineData(2.71828183f, 1.41421356f, 4.11325038f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (sqrt(2)) + [InlineData(2.71828183f, 1.44269504f, 4.23208611f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (log2(e)) + [InlineData(2.71828183f, 1.57079633f, 4.81047738f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (pi / 2) + [InlineData(2.71828183f, 2.30258509f, 10.0f, CrossPlatformMachineEpsilon * 100)] // x: (e) y: (ln(10)) + [InlineData(2.71828183f, 2.71828183f, 15.1542622f, CrossPlatformMachineEpsilon * 100)] // x: (e) y: (e) + [InlineData(2.71828183f, 3.14159265f, 23.1406926f, CrossPlatformMachineEpsilon * 100)] // x: (e) y: (pi) + [InlineData(2.71828183f, float.PositiveInfinity, float.PositiveInfinity, 0.0f)] // x: (e) + [InlineData(10.0f, float.NegativeInfinity, 0.0f, 0.0f)] + [InlineData(10.0f, -3.14159265f, 0.000721784159f, CrossPlatformMachineEpsilon / 1000)] // y: -(pi) + [InlineData(10.0f, -2.71828183f, 0.00191301410f, CrossPlatformMachineEpsilon / 100)] // y: -(e) + [InlineData(10.0f, -2.30258509f, 0.00498212830f, CrossPlatformMachineEpsilon / 100)] // y: -(ln(10)) + [InlineData(10.0f, -1.57079633f, 0.0268660410f, CrossPlatformMachineEpsilon / 10)] // y: -(pi / 2) + [InlineData(10.0f, -1.44269504f, 0.0360831928f, CrossPlatformMachineEpsilon / 10)] // y: -(log2(e)) + [InlineData(10.0f, -1.41421356f, 0.0385288847f, CrossPlatformMachineEpsilon / 10)] // y: -(sqrt(2)) + [InlineData(10.0f, -1.12837917f, 0.0744082059f, CrossPlatformMachineEpsilon / 10)] // y: -(2 / sqrt(pi)) + [InlineData(10.0f, -1.0f, 0.1f, CrossPlatformMachineEpsilon)] + [InlineData(10.0f, -0.785398163f, 0.163908636f, CrossPlatformMachineEpsilon)] // y: -(pi / 4) + [InlineData(10.0f, -0.707106781f, 0.196287760f, CrossPlatformMachineEpsilon)] // y: -(1 / sqrt(2)) + [InlineData(10.0f, -0.693147181f, 0.202699566f, CrossPlatformMachineEpsilon)] // y: -(ln(2)) + [InlineData(10.0f, -0.636619772f, 0.230876765f, CrossPlatformMachineEpsilon)] // y: -(2 / pi) + [InlineData(10.0f, -0.434294482f, 0.367879441f, CrossPlatformMachineEpsilon)] // y: -(log10(e)) + [InlineData(10.0f, -0.318309886f, 0.480496373f, CrossPlatformMachineEpsilon)] // y: -(1 / pi) + [InlineData(10.0f, -0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(10.0f, float.NaN, float.NaN, 0.0f)] + [InlineData(10.0f, 0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(10.0f, 0.318309886f, 2.08118116f, CrossPlatformMachineEpsilon * 10)] // y: (1 / pi) + [InlineData(10.0f, 0.434294482f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // y: (log10(e)) expected: (e) + [InlineData(10.0f, 0.636619772f, 4.33131503f, CrossPlatformMachineEpsilon * 10)] // y: (2 / pi) + [InlineData(10.0f, 0.693147181f, 4.93340967f, CrossPlatformMachineEpsilon * 10)] // y: (ln(2)) + [InlineData(10.0f, 0.707106781f, 5.09456117f, CrossPlatformMachineEpsilon * 10)] // y: (1 / sqrt(2)) + [InlineData(10.0f, 0.785398163f, 6.10095980f, CrossPlatformMachineEpsilon * 10)] // y: (pi / 4) + [InlineData(10.0f, 1.0f, 10.0f, CrossPlatformMachineEpsilon * 100)] + [InlineData(10.0f, 1.12837917f, 13.4393779f, CrossPlatformMachineEpsilon * 100)] // y: (2 / sqrt(pi)) + [InlineData(10.0f, 1.41421356f, 25.9545535f, CrossPlatformMachineEpsilon * 100)] // y: (sqrt(2)) + [InlineData(10.0f, 1.44269504f, 27.7137338f, CrossPlatformMachineEpsilon * 100)] // y: (log2(e)) + [InlineData(10.0f, 1.57079633f, 37.2217105f, CrossPlatformMachineEpsilon * 100)] // y: (pi / 2) + [InlineData(10.0f, 2.30258509f, 200.717432f, CrossPlatformMachineEpsilon * 1000)] // y: (ln(10)) + [InlineData(10.0f, 2.71828183f, 522.735300f, CrossPlatformMachineEpsilon * 1000)] // y: (e) + [InlineData(10.0f, 3.14159265f, 1385.45573f, CrossPlatformMachineEpsilon * 10000)] // y: (pi) + [InlineData(10.0f, float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + [InlineData(float.PositiveInfinity, float.NegativeInfinity, 0.0f, 0.0f)] + [InlineData(float.PositiveInfinity, -1.0f, 0.0f, 0.0f)] + [InlineData(float.PositiveInfinity, -0.0f, 1.0f, 0.0f)] + [InlineData(float.PositiveInfinity, float.NaN, float.NaN, 0.0f)] + [InlineData(float.PositiveInfinity, 0.0f, 1.0f, 0.0f)] + [InlineData(float.PositiveInfinity, 1.0f, float.PositiveInfinity, 0.0f)] + [InlineData(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Pow(float x, float y, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Pow(x, y), allowedVariance); + } + + public static IEnumerable Round_Digits_TestData + { + get + { + yield return new object[] { float.NaN, float.NaN, 3, MidpointRounding.ToEven }; + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, 3, MidpointRounding.ToEven }; + yield return new object[] { float.NegativeInfinity, float.NegativeInfinity, 3, MidpointRounding.ToEven }; + yield return new object[] { 0, 0, 3, MidpointRounding.ToEven }; + yield return new object[] { 3.42156f, 3.422f, 3, MidpointRounding.ToEven }; + yield return new object[] { -3.42156f, -3.422f, 3, MidpointRounding.ToEven }; + + yield return new object[] { float.NaN, float.NaN, 3, MidpointRounding.AwayFromZero }; + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, 3, MidpointRounding.AwayFromZero }; + yield return new object[] { float.NegativeInfinity, float.NegativeInfinity, 3, MidpointRounding.AwayFromZero }; + yield return new object[] { 0, 0, 3, MidpointRounding.AwayFromZero }; + yield return new object[] { 3.42156f, 3.422f, 3, MidpointRounding.AwayFromZero }; + yield return new object[] { -3.42156f, -3.422f, 3, MidpointRounding.AwayFromZero }; + } + } + + [Fact] + public static void Round() + { + Assert.Equal(0.0f, MathF.Round(0.0f)); + Assert.Equal(1.0f, MathF.Round(1.4f)); + Assert.Equal(2.0f, MathF.Round(1.5f)); + Assert.Equal(2e7f, MathF.Round(2e7f)); + Assert.Equal(0.0f, MathF.Round(-0.0f)); + Assert.Equal(-1.0f, MathF.Round(-1.4f)); + Assert.Equal(-2.0f, MathF.Round(-1.5f)); + Assert.Equal(-2e7f, MathF.Round(-2e7f)); + } + + [Theory] + [InlineData(MidpointRounding.ToEven)] + [InlineData(MidpointRounding.AwayFromZero)] + public static void Round_Digits_ByMidpointRounding(MidpointRounding mode) + { + Assert.Equal(float.PositiveInfinity, MathF.Round(float.PositiveInfinity, 3, mode)); + Assert.Equal(float.NegativeInfinity, MathF.Round(float.NegativeInfinity, 3, mode)); + } + + [Theory] + [MemberData(nameof(Round_Digits_TestData))] + public static void Round_Digits(float x, float expected, int digits, MidpointRounding mode) + { + AssertExtensions.Equal(expected, MathF.Round(x, digits, mode), CrossPlatformMachineEpsilon * 10); + } + + [Fact] + public static void Sign() + { + Assert.Equal(0, MathF.Sign(0.0f)); + Assert.Equal(0, MathF.Sign(-0.0f)); + Assert.Equal(-1, MathF.Sign(-3.14f)); + Assert.Equal(1, MathF.Sign(3.14f)); + Assert.Equal(-1, MathF.Sign(float.NegativeInfinity)); + Assert.Equal(1, MathF.Sign(float.PositiveInfinity)); + Assert.Throws(() => MathF.Sign(float.NaN)); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(-3.14159265f, -0.0f, CrossPlatformMachineEpsilon)] // value: -(pi) + [InlineData(-2.71828183f, -0.410781291f, CrossPlatformMachineEpsilon)] // value: -(e) + [InlineData(-2.30258509f, -0.743980337f, CrossPlatformMachineEpsilon)] // value: -(ln(10)) + [InlineData(-1.57079633f, -1.0f, CrossPlatformMachineEpsilon * 10)] // value: -(pi / 2) + [InlineData(-1.44269504f, -0.991806244f, CrossPlatformMachineEpsilon)] // value: -(log2(e)) + [InlineData(-1.41421356f, -0.987765946f, CrossPlatformMachineEpsilon)] // value: -(sqrt(2)) + [InlineData(-1.12837917f, -0.903719457f, CrossPlatformMachineEpsilon)] // value: -(2 / sqrt(pi)) + [InlineData(-1.0f, -0.841470985f, CrossPlatformMachineEpsilon)] + [InlineData(-0.785398163f, -0.707106781f, CrossPlatformMachineEpsilon)] // value: -(pi / 4), expected: -(1 / sqrt(2)) + [InlineData(-0.707106781f, -0.649636939f, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) + [InlineData(-0.693147181f, -0.638961276f, CrossPlatformMachineEpsilon)] // value: -(ln(2)) + [InlineData(-0.636619772f, -0.594480769f, CrossPlatformMachineEpsilon)] // value: -(2 / pi) + [InlineData(-0.434294482f, -0.420770483f, CrossPlatformMachineEpsilon)] // value: -(log10(e)) + [InlineData(-0.318309886f, -0.312961796f, CrossPlatformMachineEpsilon)] // value: -(1 / pi) + [InlineData(-0.0f, -0.0f, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 0.312961796f, CrossPlatformMachineEpsilon)] // value: (1 / pi) + [InlineData(0.434294482f, 0.420770483f, CrossPlatformMachineEpsilon)] // value: (log10(e)) + [InlineData(0.636619772f, 0.594480769f, CrossPlatformMachineEpsilon)] // value: (2 / pi) + [InlineData(0.693147181f, 0.638961276f, CrossPlatformMachineEpsilon)] // value: (ln(2)) + [InlineData(0.707106781f, 0.649636939f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 0.707106781f, CrossPlatformMachineEpsilon)] // value: (pi / 4), expected: (1 / sqrt(2)) + [InlineData(1.0f, 0.841470985f, CrossPlatformMachineEpsilon)] + [InlineData(1.12837917f, 0.903719457f, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 0.987765946f, CrossPlatformMachineEpsilon)] // value: (sqrt(2)) + [InlineData(1.44269504f, 0.991806244f, CrossPlatformMachineEpsilon)] // value: (log2(e)) + [InlineData(1.57079633f, 1.0f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2) + [InlineData(2.30258509f, 0.743980337f, CrossPlatformMachineEpsilon)] // value: (ln(10)) + [InlineData(2.71828183f, 0.410781291f, CrossPlatformMachineEpsilon)] // value: (e) + [InlineData(3.14159265f, 0.0f, CrossPlatformMachineEpsilon)] // value: (pi) + [InlineData(float.PositiveInfinity, float.NaN, 0.0f)] + public static void Sin(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Sin(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NegativeInfinity, 0.0f)] + [InlineData(-3.14159265f, -11.5487394f, CrossPlatformMachineEpsilon * 100)] // value: -(pi) + [InlineData(-2.71828183f, -7.54413710f, CrossPlatformMachineEpsilon * 10)] // value: -(e) + [InlineData(-2.30258509f, -4.95f, CrossPlatformMachineEpsilon * 10)] // value: -(ln(10)) + [InlineData(-1.57079633f, -2.30129890f, CrossPlatformMachineEpsilon * 10)] // value: -(pi / 2) + [InlineData(-1.44269504f, -1.99789801f, CrossPlatformMachineEpsilon * 10)] // value: -(log2(e)) + [InlineData(-1.41421356f, -1.93506682f, CrossPlatformMachineEpsilon * 10)] // value: -(sqrt(2)) + [InlineData(-1.12837917f, -1.38354288f, CrossPlatformMachineEpsilon * 10)] // value: -(2 / sqrt(pi)) + [InlineData(-1.0f, -1.17520119f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-0.785398163f, -0.868670961f, CrossPlatformMachineEpsilon)] // value: -(pi / 4) + [InlineData(-0.707106781f, -0.767523145f, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) + [InlineData(-0.693147181f, -0.75f, CrossPlatformMachineEpsilon)] // value: -(ln(2)) + [InlineData(-0.636619772f, -0.680501678f, CrossPlatformMachineEpsilon)] // value: -(2 / pi) + [InlineData(-0.434294482f, -0.448075979f, CrossPlatformMachineEpsilon)] // value: -(log10(e)) + [InlineData(-0.318309886f, -0.323712439f, CrossPlatformMachineEpsilon)] // value: -(1 / pi) + [InlineData(-0.0f, -0.0f, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 0.323712439f, CrossPlatformMachineEpsilon)] // value: (1 / pi) + [InlineData(0.434294482f, 0.448075979f, CrossPlatformMachineEpsilon)] // value: (log10(e)) + [InlineData(0.636619772f, 0.680501678f, CrossPlatformMachineEpsilon)] // value: (2 / pi) + [InlineData(0.693147181f, 0.75f, CrossPlatformMachineEpsilon)] // value: (ln(2)) + [InlineData(0.707106781f, 0.767523145f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 0.868670961f, CrossPlatformMachineEpsilon)] // value: (pi / 4) + [InlineData(1.0f, 1.17520119f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.12837917f, 1.38354288f, CrossPlatformMachineEpsilon * 10)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 1.93506682f, CrossPlatformMachineEpsilon * 10)] // value: (sqrt(2)) + [InlineData(1.44269504f, 1.99789801f, CrossPlatformMachineEpsilon * 10)] // value: (log2(e)) + [InlineData(1.57079633f, 2.30129890f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2) + [InlineData(2.30258509f, 4.95f, CrossPlatformMachineEpsilon * 10)] // value: (ln(10)) + [InlineData(2.71828183f, 7.54413710f, CrossPlatformMachineEpsilon * 10)] // value: (e) + [InlineData(3.14159265f, 11.5487394f, CrossPlatformMachineEpsilon * 100)] // value: (pi) + [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Sinh(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Sinh(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(-3.14159265f, float.NaN, 0.0f)] // value: (pi) + [InlineData(-2.71828183f, float.NaN, 0.0f)] // value: (e) + [InlineData(-2.30258509f, float.NaN, 0.0f)] // value: (ln(10)) + [InlineData(-1.57079633f, float.NaN, 0.0f)] // value: (pi / 2) + [InlineData(-1.44269504f, float.NaN, 0.0f)] // value: (log2(e)) + [InlineData(-1.41421356f, float.NaN, 0.0f)] // value: (sqrt(2)) + [InlineData(-1.12837917f, float.NaN, 0.0f)] // value: (2 / sqrt(pi)) + [InlineData(-1.0f, float.NaN, 0.0f)] + [InlineData(-0.785398163f, float.NaN, 0.0f)] // value: (pi / 4) + [InlineData(-0.707106781f, float.NaN, 0.0f)] // value: (1 / sqrt(2)) + [InlineData(-0.693147181f, float.NaN, 0.0f)] // value: (ln(2)) + [InlineData(-0.636619772f, float.NaN, 0.0f)] // value: (2 / pi) + [InlineData(-0.434294482f, float.NaN, 0.0f)] // value: (log10(e)) + [InlineData(-0.318309886f, float.NaN, 0.0f)] // value: (1 / pi) + [InlineData(-0.0f, -0.0f, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 0.564189584f, CrossPlatformMachineEpsilon)] // value: (1 / pi) + [InlineData(0.434294482f, 0.659010229f, CrossPlatformMachineEpsilon)] // value: (log10(e)) + [InlineData(0.636619772f, 0.797884561f, CrossPlatformMachineEpsilon)] // value: (2 / pi) + [InlineData(0.693147181f, 0.832554611f, CrossPlatformMachineEpsilon)] // value: (ln(2)) + [InlineData(0.707106781f, 0.840896415f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 0.886226925f, CrossPlatformMachineEpsilon)] // value: (pi / 4) + [InlineData(1.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.12837917f, 1.06225193f, CrossPlatformMachineEpsilon * 10)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 1.18920712f, CrossPlatformMachineEpsilon * 10)] // value: (sqrt(2)) + [InlineData(1.44269504f, 1.20112241f, CrossPlatformMachineEpsilon * 10)] // value: (log2(e)) + [InlineData(1.57079633f, 1.25331414f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2) + [InlineData(2.30258509f, 1.51742713f, CrossPlatformMachineEpsilon * 10)] // value: (ln(10)) + [InlineData(2.71828183f, 1.64872127f, CrossPlatformMachineEpsilon * 10)] // value: (e) + [InlineData(3.14159265f, 1.77245385F, CrossPlatformMachineEpsilon * 10)] // value: (pi) + [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Sqrt(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Sqrt(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(-3.14159265f, -0.0f, CrossPlatformMachineEpsilon)] // value: -(pi) + [InlineData(-2.71828183f, 0.450549534f, CrossPlatformMachineEpsilon)] // value: -(e) + [InlineData(-2.30258509f, 1.11340715f, CrossPlatformMachineEpsilon * 10)] // value: -(ln(10)) + [InlineData(-1.57079633f, 22877332.0f, 10.0f)] // value: -(pi / 2) + [InlineData(-1.44269504f, -7.76357567f, CrossPlatformMachineEpsilon * 10)] // value: -(log2(e)) + [InlineData(-1.41421356f, -6.33411917f, CrossPlatformMachineEpsilon * 10)] // value: -(sqrt(2)) + [InlineData(-1.12837917f, -2.11087684f, CrossPlatformMachineEpsilon * 10)] // value: -(2 / sqrt(pi)) + [InlineData(-1.0f, -1.55740772f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-0.785398163f, -1.0f, CrossPlatformMachineEpsilon * 10)] // value: -(pi / 4) + [InlineData(-0.707106781f, -0.854510432f, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) + [InlineData(-0.693147181f, -0.830640878f, CrossPlatformMachineEpsilon)] // value: -(ln(2)) + [InlineData(-0.636619772f, -0.739302950f, CrossPlatformMachineEpsilon)] // value: -(2 / pi) + [InlineData(-0.434294482f, -0.463829067f, CrossPlatformMachineEpsilon)] // value: -(log10(e)) + [InlineData(-0.318309886f, -0.329514733f, CrossPlatformMachineEpsilon)] // value: -(1 / pi) + [InlineData(-0.0f, -0.0f, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 0.329514733f, CrossPlatformMachineEpsilon)] // value: (1 / pi) + [InlineData(0.434294482f, 0.463829067f, CrossPlatformMachineEpsilon)] // value: (log10(e)) + [InlineData(0.636619772f, 0.739302950f, CrossPlatformMachineEpsilon)] // value: (2 / pi) + [InlineData(0.693147181f, 0.830640878f, CrossPlatformMachineEpsilon)] // value: (ln(2)) + [InlineData(0.707106781f, 0.854510432f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 1.0f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 4) + [InlineData(1.0f, 1.55740772f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.12837917f, 2.11087684f, CrossPlatformMachineEpsilon * 10)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 6.33411917f, CrossPlatformMachineEpsilon * 10)] // value: (sqrt(2)) + [InlineData(1.44269504f, 7.76357567f, CrossPlatformMachineEpsilon * 10)] // value: (log2(e)) + [InlineData(1.57079633f, -22877332.0f, 10.0f)] // value: (pi / 2) + [InlineData(2.30258509f, -1.11340715f, CrossPlatformMachineEpsilon * 10)] // value: (ln(10)) + [InlineData(2.71828183f, -0.450549534f, CrossPlatformMachineEpsilon)] // value: (e) + [InlineData(3.14159265f, 0.0f, CrossPlatformMachineEpsilon)] // value: (pi) + [InlineData(float.PositiveInfinity, float.NaN, 0.0f)] + public static void Tan(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Tan(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, -1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-3.14159265f, -0.996272076f, CrossPlatformMachineEpsilon)] // value: -(pi) + [InlineData(-2.71828183f, -0.991328916f, CrossPlatformMachineEpsilon)] // value: -(e) + [InlineData(-2.30258509f, -0.980198020f, CrossPlatformMachineEpsilon)] // value: -(ln(10)) + [InlineData(-1.57079633f, -0.917152336f, CrossPlatformMachineEpsilon)] // value: -(pi / 2) + [InlineData(-1.44269504f, -0.894238946f, CrossPlatformMachineEpsilon)] // value: -(log2(e)) + [InlineData(-1.41421356f, -0.888385562f, CrossPlatformMachineEpsilon)] // value: -(sqrt(2)) + [InlineData(-1.12837917f, -0.810463806f, CrossPlatformMachineEpsilon)] // value: -(2 / sqrt(pi)) + [InlineData(-1.0f, -0.761594156f, CrossPlatformMachineEpsilon)] + [InlineData(-0.785398163f, -0.655794203f, CrossPlatformMachineEpsilon)] // value: -(pi / 4) + [InlineData(-0.707106781f, -0.608859365f, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) + [InlineData(-0.693147181f, -0.6f, CrossPlatformMachineEpsilon)] // value: -(ln(2)) + [InlineData(-0.636619772f, -0.562593600f, CrossPlatformMachineEpsilon)] // value: -(2 / pi) + [InlineData(-0.434294482f, -0.408904012f, CrossPlatformMachineEpsilon)] // value: -(log10(e)) + [InlineData(-0.318309886f, -0.307977913f, CrossPlatformMachineEpsilon)] // value: -(1 / pi) + [InlineData(-0.0f, -0.0f, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 0.307977913f, CrossPlatformMachineEpsilon)] // value: (1 / pi) + [InlineData(0.434294482f, 0.408904012f, CrossPlatformMachineEpsilon)] // value: (log10(e)) + [InlineData(0.636619772f, 0.562593600f, CrossPlatformMachineEpsilon)] // value: (2 / pi) + [InlineData(0.693147181f, 0.6f, CrossPlatformMachineEpsilon)] // value: (ln(2)) + [InlineData(0.707106781f, 0.608859365f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 0.655794203f, CrossPlatformMachineEpsilon)] // value: (pi / 4) + [InlineData(1.0f, 0.761594156f, CrossPlatformMachineEpsilon)] + [InlineData(1.12837917f, 0.810463806f, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 0.888385562f, CrossPlatformMachineEpsilon)] // value: (sqrt(2)) + [InlineData(1.44269504f, 0.894238946f, CrossPlatformMachineEpsilon)] // value: (log2(e)) + [InlineData(1.57079633f, 0.917152336f, CrossPlatformMachineEpsilon)] // value: (pi / 2) + [InlineData(2.30258509f, 0.980198020f, CrossPlatformMachineEpsilon)] // value: (ln(10)) + [InlineData(2.71828183f, 0.991328916f, CrossPlatformMachineEpsilon)] // value: (e) + [InlineData(3.14159265f, 0.996272076f, CrossPlatformMachineEpsilon)] // value: (pi) + [InlineData(float.PositiveInfinity, 1.0f, CrossPlatformMachineEpsilon * 10)] + public static void Tanh(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Tanh(value), allowedVariance); + } + + [Fact] + public static void Truncate() + { + Assert.Equal(0.0f, MathF.Truncate(0.12345f)); + Assert.Equal(3.0f, MathF.Truncate(3.14159f)); + Assert.Equal(-3.0f, MathF.Truncate(-3.14159f)); + } + + public static IEnumerable Round_ToEven_TestData() + { + yield return new object[] { 1f, 1f }; + yield return new object[] { 0.5f, 0f }; + yield return new object[] { 1.5f, 2f }; + yield return new object[] { 2.5f, 2f }; + yield return new object[] { 3.5f, 4f }; + yield return new object[] { 0.49999997f, 0f }; + yield return new object[] { 1.5f, 2f }; + yield return new object[] { 2.5f, 2f }; + yield return new object[] { 3.5f, 4f }; + yield return new object[] { 4.5f, 4f }; + yield return new object[] { 3.1415927f, 3f }; + yield return new object[] { 2.7182817f, 3f }; + yield return new object[] { 1385.4557f, 1385f }; + yield return new object[] { 3423.4343f, 3423f }; + yield return new object[] { 535345.5f, 535346f }; + yield return new object[] { 535345.5f, 535346f }; + yield return new object[] { 535345.5f, 535346f }; + yield return new object[] { 535345.4f, 535345f }; + yield return new object[] { 535345.6f, 535346f }; + yield return new object[] { -2.7182817f, -3f }; + yield return new object[] { 10f, 10f }; + yield return new object[] { -10f, -10f }; + yield return new object[] { -0f, -0f }; + yield return new object[] { 0f, 0f }; + yield return new object[] { float.NaN, float.NaN }; + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { 3.4028235E+38f, 3.4028235E+38f }; + yield return new object[] { -3.4028235E+38f, -3.4028235E+38f }; + } + + [Theory] + [MemberData(nameof(Round_ToEven_TestData))] + public static void Round_ToEven_0(float value, float expected) + { + // Math.Round has special fast paths when MidpointRounding is a const + // Don't replace it with a variable + Assert.Equal(expected, MathF.Round(value, MidpointRounding.ToEven)); + Assert.Equal(expected, MathF.Round(value, 0, MidpointRounding.ToEven)); + } + + public static IEnumerable Round_AwayFromZero_TestData() + { + yield return new object[] { 1f, 1f }; + yield return new object[] { 0.5f, 1f }; + yield return new object[] { 1.5f, 2f }; + yield return new object[] { 2.5f, 3f }; + yield return new object[] { 3.5f, 4f }; + yield return new object[] { 0.49999997f, 0f }; + yield return new object[] { 1.5f, 2f }; + yield return new object[] { 2.5f, 3f }; + yield return new object[] { 3.5f, 4f }; + yield return new object[] { 4.5f, 5f }; + yield return new object[] { 3.1415927f, 3f }; + yield return new object[] { 2.7182817f, 3f }; + yield return new object[] { 1385.4557f, 1385f }; + yield return new object[] { 3423.4343f, 3423f }; + yield return new object[] { 535345.5f, 535346f }; + yield return new object[] { 535345.5f, 535346f }; + yield return new object[] { 535345.5f, 535346f }; + yield return new object[] { 535345.4f, 535345f }; + yield return new object[] { 535345.6f, 535346f }; + yield return new object[] { -2.7182817f, -3f }; + yield return new object[] { 10f, 10f }; + yield return new object[] { -10f, -10f }; + yield return new object[] { -0f, -0f }; + yield return new object[] { 0f, 0f }; + yield return new object[] { float.NaN, float.NaN }; + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { 3.4028235E+38f, 3.4028235E+38f }; + yield return new object[] { -3.4028235E+38f, -3.4028235E+38f }; + } + + [Theory] + [MemberData(nameof(Round_AwayFromZero_TestData))] + public static void Round_AwayFromZero_0(float value, float expected) + { + // Math.Round has special fast paths when MidpointRounding is a const + // Don't replace it with a variable + Assert.Equal(expected, MathF.Round(value, MidpointRounding.AwayFromZero)); + Assert.Equal(expected, MathF.Round(value, 0, MidpointRounding.AwayFromZero)); + } + } +} diff --git a/src/libraries/Microsoft.Bcl.Numerics/tests/Microsoft.Bcl.Numerics.Tests.csproj b/src/libraries/Microsoft.Bcl.Numerics/tests/Microsoft.Bcl.Numerics.Tests.csproj new file mode 100644 index 0000000000000..24bf98fa16671 --- /dev/null +++ b/src/libraries/Microsoft.Bcl.Numerics/tests/Microsoft.Bcl.Numerics.Tests.csproj @@ -0,0 +1,15 @@ + + + + $(NetFrameworkMinimum) + + + + + + + + + + +