diff options
Diffstat (limited to 'src/mscorlib/src/System/MathF.cs')
-rw-r--r-- | src/mscorlib/src/System/MathF.cs | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/MathF.cs b/src/mscorlib/src/System/MathF.cs new file mode 100644 index 0000000000..fb800924b5 --- /dev/null +++ b/src/mscorlib/src/System/MathF.cs @@ -0,0 +1,253 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*============================================================ +** +** Purpose: Some single-precision floating-point math operations +** +===========================================================*/ +namespace System { + + //This class contains only static members and doesn't require serialization. + using System; + using System.Runtime; + using System.Runtime.CompilerServices; + using System.Runtime.ConstrainedExecution; + using System.Runtime.Versioning; + using System.Diagnostics.Contracts; + + public static class MathF + { + private static float singleRoundLimit = 1e8f; + + private const int maxRoundingDigits = 6; + + // This table is required for the Round function which can specify the number of digits to round to + private static float[] roundPower10Single = new float[] { + 1e0f, 1e1f, 1e2f, 1e3f, 1e4f, 1e5f, 1e6f + }; + + public const float PI = 3.14159265f; + + public const float E = 2.71828183f; + + public static float Abs(float x) => Math.Abs(x); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern float Acos(float x); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern float Asin(float x); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern float Atan(float x); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern float Atan2(float y, float x); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern float Ceiling(float x); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern float Cos(float x); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern float Cosh(float x); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern float Exp(float x); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern float Floor(float x); + + 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) && float.IsNegative(x)) + { + return float.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; + } + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern float Log(float x); + + 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); + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern float Log10(float x); + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public static float Max(float x, float y) => Math.Max(x, y); + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + public static float Min(float x, float y) => Math.Min(x, y); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern float Pow(float x, float y); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern float Round(float x); + + public static float Round(float x, int digits) + { + if ((digits < 0) || (digits > maxRoundingDigits)) + { + throw new ArgumentOutOfRangeException(nameof(digits), Environment.GetResourceString("ArgumentOutOfRange_RoundingDigits")); + } + Contract.EndContractBlock(); + + return InternalRound(x, digits, MidpointRounding.ToEven); + } + + public static float Round(float x, int digits, MidpointRounding mode) + { + if ((digits < 0) || (digits > maxRoundingDigits)) + { + throw new ArgumentOutOfRangeException(nameof(digits), Environment.GetResourceString("ArgumentOutOfRange_RoundingDigits")); + } + + if (mode < MidpointRounding.ToEven || mode > MidpointRounding.AwayFromZero) + { + throw new ArgumentException(Environment.GetResourceString("Argument_InvalidEnumx", mode, nameof(MidpointRounding)), nameof(mode)); + } + Contract.EndContractBlock(); + + return InternalRound(x, digits, mode); + } + + public static float Round(float x, MidpointRounding mode) + { + if (mode < MidpointRounding.ToEven || mode > MidpointRounding.AwayFromZero) + { + throw new ArgumentException(Environment.GetResourceString("Argument_InvalidEnumx", mode, nameof(MidpointRounding)), nameof(mode)); + } + Contract.EndContractBlock(); + + return InternalRound(x, 0, mode); + } + + public static int Sign(float x) => Math.Sign(x); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern float Sin(float x); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern float Sinh(float x); + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern float Sqrt(float x); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern float Tan(float x); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern float Tanh(float x); + + public static float Truncate(float x) => InternalTruncate(x); + + private static unsafe float InternalRound(float x, int digits, MidpointRounding mode) + { + if (Abs(x) < singleRoundLimit) + { + var power10 = roundPower10Single[digits]; + + x *= power10; + + if (mode == MidpointRounding.AwayFromZero) + { + var fraction = SplitFractionSingle(&x); + + if (Abs(fraction) >= 0.5f) + { + x += Sign(fraction); + } + } + else + { + x = Round(x); + } + + x /= power10; + } + + return x; + } + + private unsafe static float InternalTruncate(float x) + { + SplitFractionSingle(&x); + return x; + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static unsafe extern float SplitFractionSingle(float* x); + } +} |