diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index c215d7a68ef259..3dc95c6bec2de4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -1449,5 +1449,239 @@ public static double ScaleB(double x, int n) double u = BitConverter.Int64BitsToDouble(((long)(0x3ff + n) << 52)); return y * u; } + + /// + /// Returns the sine of the specified angle measured in half-revolutions. + /// + /// An angle, measured in half-revolutions. + /// The sine of . If is equal to , , + /// or , this method returns . + /// + /// This method is effectively Sin(x * PI), with higher precision. + /// It guarantees to return -1, 0, or 1 when is integer or half-integer. + /// + public static double SinPi(double x) + { + if (Abs(x) < 0.5 || !double.IsFinite(x)) + { + // Fast path for small/special values, also covers +0/-0 + return Sin(x * PI); + } + + bool invert = false; + if (x < 0) + { + x = -x; + invert = true; + } + + double floor = Floor(x); + if (x == floor) + { + // +0 for +n and -0 for -n + return invert ? -0.0 : 0.0; + } + + // fold all input into (0, 0.5] + if (((long)floor & 1) != 0) + { + // sin(x + PI) = -sin(x) + invert = !invert; + } + + double rem = x - floor; + if (rem == 0.5) + { + return invert ? -1 : 1; + } + + if (rem > 0.5) + { + // sin(PI - x) = sin(x) + rem = 1 - rem; + } + + double sin = Sin(rem * PI); + return invert ? -sin : sin; + } + + /// + /// Returns the cosine of the specified angle measured in half-revolutions. + /// + /// An angle, measured in half-revolutions. + /// The cosine of . If is equal to , , + /// or , this method returns . + /// + /// This method is effectively Cos(x * PI), with higher precision. + /// It guarantees to return -1, 0, or 1 when is integer or half-integer. + /// + public static double CosPi(double x) + { + if (Abs(x) < 0.5 || !double.IsFinite(x)) + { + // Fast path for small/special values, also covers +0/-0 + return Cos(x * PI); + } + + bool invert = false; + if (x < 0) + { + x = -x; + } + + double floor = Floor(x); + + // fold all input into [0, 0.5] + if (((long)floor & 1) != 0) + { + // cos(x + PI) = -cos(x) + invert = !invert; + } + + if (x == floor) + { + return invert ? -1 : 1; + } + + double rem = x - floor; + if (rem == 0.5) + { + return 0.0; + } + + if (rem > 0.5) + { + // cos(PI - x) = -cos(x) + rem = 1 - rem; + invert = !invert; + } + + double cos = Cos(rem * PI); + return invert ? -cos : cos; + } + + /// + /// Returns the tangent of the specified angle measured in half-revolutions. + /// + /// An angle, measured in half-revolutions. + /// The tangent of . If is equal to , , + /// or , this method returns . + /// + /// This method is effectively Tan(x * PI), with higher precision. + /// It guarantees to return 0, or when is integer or half-integer. + /// + public static double TanPi(double x) + { + if (Abs(x) < 0.5 || !double.IsFinite(x)) + { + // Fast path for small/special values, also covers +0/-0 + return Tan(x * PI); + } + + bool invert = false; + if (x < 0) + { + x = -x; + invert = true; + } + + double floor = Floor(x); + if (x == floor) + { + // +0 for +2n and -0 for +2n+1 + // -0 for -2n and +0 for -2n-1 + if (((long)floor & 1) != 0) + { + invert = !invert; + } + return invert ? -0.0 : 0.0; + } + + // fold all input into (0, 0.5] + double rem = x - floor; + if (rem == 0.5) + { + // +inf for +2n+0.5 and -inf for +2n+1.5 + // -inf for -2n-0.5 and +inf for -2n-1.5 + if (((long)floor & 1) != 0) + { + invert = !invert; + } + return invert ? double.NegativeInfinity : double.PositiveInfinity; + } + + if (rem > 0.5) + { + // tan(PI - x) = -tan(x) + rem = 1 - rem; + invert = !invert; + } + + double tan = Tan(rem * PI); + return invert ? -tan : tan; + } + + // Double inverse-trigs pass all special value tests on all platforms. + // Keep them fast. + + /// + /// Returns the angle measured in half-revolutions whose sine is the specified number. + /// + /// A number representing a sine, where must be greater than or equal to -1, but + /// less than or equal to 1. + /// An angle, θ, measured in half-revolutions, such that -0.5 ≤ θ ≤ 0.5. + /// -or- + /// if < -1 or > 1 + /// or equals . + public static double AsinPi(double x) => Asin(x) / PI; + + /// + /// Returns the angle measured in half-revolutions whose cosine is the specified number. + /// + /// A number representing a cosine, where must be greater than or equal to -1, but + /// less than or equal to 1. + /// An angle, θ, measured in half-revolutions, such that -0.5 ≤ θ ≤ 0.5. + /// -or- + /// if < -1 or > 1 + /// or equals . + public static double AcosPi(double x) => Acos(x) / PI; + + /// + /// Returns the angle measured in half-revolutions whose tangent is the specified number. + /// + /// A number representing a tangent. + /// An angle, θ, measured in half-revolutions, such that -0.5 ≤ θ ≤ 0.5. + /// -or- + /// if equals , + /// -0.5 if equals , + /// or 0.5 if equals . + public static double AtanPi(double x) => Atan(x) / PI; + + /// + /// Returns the angle whose measured in half-revolutions tangent is the quotient of two specified numbers. + /// + /// The y coordinate of a point. + /// The x coordinate of a point. + /// An angle, θ, measured in half-revolutions, such that -1 ≤ θ ≤ 1, and tan(θ) = y / x, + /// where (x, y) is a point in the Cartesian plane. Observe the following: + /// + /// For (x, y) in quadrant 1, 0 < θ < 0.5. + /// For (x, y) in quadrant 2, 0.5 < θ ≤ 1. + /// For (x, y) in quadrant 3, -1 < θ < -0.5. + /// For (x, y) in quadrant 4, -0.5 < θ < 0. + /// + /// For points on the boundaries of the quadrants, the return value is the following: + /// + /// If y is 0 and x is not negative, θ = 0. + /// If y is 0 and x is negative, θ = 1. + /// If y is positive and x is 0, θ = 0.5. + /// If y is negative and x is 0, θ = -0.5. + /// If y is 0 and x is 0, θ = 0. + /// If y is 0 and x is 0, θ = 0. + /// + /// If x or y is , or if x and y are either + /// or , + /// the method returns . + public static double Atan2Pi(double y, double x) => Atan2(y, x) / PI; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/MathF.cs b/src/libraries/System.Private.CoreLib/src/System/MathF.cs index 0050f5d43368cc..26ab3c680d4ad3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/MathF.cs +++ b/src/libraries/System.Private.CoreLib/src/System/MathF.cs @@ -519,5 +519,286 @@ public static float ScaleB(float x, int n) float u = BitConverter.Int32BitsToSingle(((int)(0x7f + n) << 23)); return y * u; } + + /// + /// Returns the sine of the specified angle measured in half-revolutions. + /// + /// An angle, measured in half-revolutions. + /// The sine of . If is equal to , , + /// or , this method returns . + /// + /// This method is effectively Sin(x * PI), with higher precision. + /// It guarantees to return -1, 0, or 1 when is integer or half-integer. + /// + public static float SinPi(float x) + { + if (Abs(x) < 0.5f || !float.IsFinite(x)) + { + // Fast path for small/special values, also covers +0/-0 + return Sin(x * PI); + } + + bool invert = false; + if (x < 0) + { + x = -x; + invert = true; + } + + float floor = Floor(x); + if (x == floor) + { + // +0 for +n and -0 for -n + return invert ? -0.0f : 0.0f; + } + + // fold all input into (0, 0.5] + if (((int)floor & 1) != 0) + { + // sin(x + PI) = -sin(x) + invert = !invert; + } + + float rem = x - floor; + if (rem == 0.5f) + { + return invert ? -1 : 1; + } + + if (rem > 0.5f) + { + // sin(PI - x) = sin(x) + rem = 1 - rem; + } + + float sin = Sin(rem * PI); + return invert ? -sin : sin; + } + + /// + /// Returns the cosine of the specified angle measured in half-revolutions. + /// + /// An angle, measured in half-revolutions. + /// The cosine of . If is equal to , , + /// or , this method returns . + /// + /// This method is effectively Cos(x * PI), with higher precision. + /// It guarantees to return -1, 0, or 1 when is integer or half-integer. + /// + public static float CosPi(float x) + { + if (Abs(x) < 0.5f || !float.IsFinite(x)) + { + // Fast path for small/special values, also covers +0/-0 + return Cos(x * PI); + } + + bool invert = false; + if (x < 0) + { + x = -x; + } + + float floor = Floor(x); + + // fold all input into [0, 0.5] + if (((int)floor & 1) != 0) + { + // cos(x + PI) = -cos(x) + invert = !invert; + } + + if (x == floor) + { + return invert ? -1 : 1; + } + + float rem = x - floor; + if (rem == 0.5f) + { + return 0.0f; + } + + if (rem > 0.5f) + { + // cos(PI - x) = -cos(x) + rem = 1 - rem; + invert = !invert; + } + + float cos = Cos(rem * PI); + return invert ? -cos : cos; + } + + /// + /// Returns the tangent of the specified angle measured in half-revolutions. + /// + /// An angle, measured in half-revolutions. + /// The tangent of . If is equal to , , + /// or , this method returns . + /// + /// This method is effectively Tan(x * PI), with higher precision. + /// It guarantees to return 0, or when is integer or half-integer. + /// + public static float TanPi(float x) + { + + if (Abs(x) < 0.5f || !float.IsFinite(x)) + { + // Fast path for small/special values, also covers +0/-0 + return Tan(x * PI); + } + + bool invert = false; + if (x < 0) + { + x = -x; + invert = true; + } + + float floor = Floor(x); + if (x == floor) + { + // +0 for +2n and -0 for +2n+1 + // -0 for -2n and +0 for -2n-1 + if (((int)floor & 1) != 0) + { + invert = !invert; + } + return invert ? -0.0f : 0.0f; + } + + // fold all input into (0, 0.5] + float rem = x - floor; + if (rem == 0.5f) + { + // +inf for +2n+0.5 and -inf for +2n+1.5 + // -inf for -2n-0.5 and +inf for -2n-1.5 + if (((long)floor & 1) != 0) + { + invert = !invert; + } + return invert ? float.NegativeInfinity : float.PositiveInfinity; + } + + if (rem > 0.5) + { + // tan(PI - x) = -tan(x) + rem = 1 - rem; + invert = !invert; + } + + float tan = Tan(rem * PI); + return invert ? -tan : tan; + } + + // Float inverse-trigs fail special value tests on some platforms. + // Special case them. + + /// + /// Returns the angle measured in half-revolutions whose sine is the specified number. + /// + /// A number representing a sine, where must be greater than or equal to -1, but + /// less than or equal to 1. + /// An angle, θ, measured in half-revolutions, such that -0.5 ≤ θ ≤ 0.5. + /// -or- + /// if < -1 or > 1 + /// or equals . + public static float AsinPi(float x) + { + if (x == 1) + { + return 0.5f; + } + if (x == -1) + { + return -0.5f; + } + + return Asin(x) / PI; + } + + /// + /// Returns the angle measured in half-revolutions whose cosine is the specified number. + /// + /// A number representing a cosine, where must be greater than or equal to -1, but + /// less than or equal to 1. + /// An angle, θ, measured in half-revolutions, such that -0.5 ≤ θ ≤ 0.5. + /// -or- + /// if < -1 or > 1 + /// or equals . + public static float AcosPi(float x) + { + if (x == 0) + { + return 0.5f; + } + + return x > 0 ? Acos(x) / PI : 1 - Acos(-x) / PI; + } + + /// + /// Returns the angle measured in half-revolutions whose tangent is the specified number. + /// + /// A number representing a tangent. + /// An angle, θ, measured in half-revolutions, such that -0.5 ≤ θ ≤ 0.5. + /// -or- + /// if equals , + /// -0.5 if equals , + /// or 0.5 if equals . + public static float AtanPi(float x) + { + if (float.IsPositiveInfinity(x)) + { + return 0.5f; + } + else if (float.IsNegativeInfinity(x)) + { + return -0.5f; + } + else + { + return Atan(x) / PI; + } + } + + /// + /// Returns the angle whose measured in half-revolutions tangent is the quotient of two specified numbers. + /// + /// The y coordinate of a point. + /// The x coordinate of a point. + /// An angle, θ, measured in half-revolutions, such that -1 ≤ θ ≤ 1, and tan(θ) = y / x, + /// where (x, y) is a point in the Cartesian plane. Observe the following: + /// + /// For (x, y) in quadrant 1, 0 < θ < 0.5. + /// For (x, y) in quadrant 2, 0.5 < θ ≤ 1. + /// For (x, y) in quadrant 3, -1 < θ < -0.5. + /// For (x, y) in quadrant 4, -0.5 < θ < 0. + /// + /// For points on the boundaries of the quadrants, the return value is the following: + /// + /// If y is 0 and x is not negative, θ = 0. + /// If y is 0 and x is negative, θ = 1. + /// If y is positive and x is 0, θ = 0.5. + /// If y is negative and x is 0, θ = -0.5. + /// If y is 0 and x is 0, θ = 0. + /// If y is 0 and x is 0, θ = 0. + /// + /// If x or y is , or if x and y are either + /// or , + /// the method returns . + public static float Atan2Pi(float y, float x) + { + float atan = Atan2(y, x) / PI; + + // if x or y is 0 or inf, it's a special value required by IEEE754:2019 + // rounding to nearist quarter-integer (keeps +0/-0) + if (x == 0 || y == 0 || float.IsInfinity(x) || float.IsInfinity(y)) + { + return Round(atan * 4) / 4; + } + + return atan; + } } } diff --git a/src/libraries/System.Runtime.Extensions/tests/System/Math.cs b/src/libraries/System.Runtime.Extensions/tests/System/Math.cs index fbe995267afea0..482ae3d190c7dc 100644 --- a/src/libraries/System.Runtime.Extensions/tests/System/Math.cs +++ b/src/libraries/System.Runtime.Extensions/tests/System/Math.cs @@ -3176,5 +3176,237 @@ public static void Round_Float_Constant_Arg() Assert.Equal( 4, MathF.Round( 3.5f, MidpointRounding.AwayFromZero)); Assert.Equal(-4, MathF.Round(-3.5f, MidpointRounding.AwayFromZero)); } + + [Fact] + public static void SinPi_Double_Precision() + { + AssertEqual( 0.0, Math.SinPi( 0.0), 0.0); + AssertEqual(-0.0, Math.SinPi(-0.0), 0.0); + AssertEqual( 1.0, Math.SinPi( 0.5), 0.0); + AssertEqual(-1.0, Math.SinPi(-0.5), 0.0); + AssertEqual( 0.0, Math.SinPi( 1.0), 0.0); + AssertEqual(-0.0, Math.SinPi(-1.0), 0.0); + AssertEqual(-1.0, Math.SinPi( 1.5), 0.0); + AssertEqual( 1.0, Math.SinPi(-1.5), 0.0); + AssertEqual( 0.0, Math.SinPi( 2.0), 0.0); + AssertEqual(-0.0, Math.SinPi(-2.0), 0.0); + + AssertEqual(0.0, Math.SinPi(0.1234) + Math.SinPi(-0.1234), 0.0); + AssertEqual(0.0, Math.SinPi(0.6789) + Math.SinPi(-0.6789), 0.0); + AssertEqual(0.0, Math.SinPi(1.2345) + Math.SinPi(-1.2345), 0.0); + } + + [Fact] + public static void SinPi_Float_Precision() + { + AssertEqual( 0.0f, MathF.SinPi( 0.0f), 0.0f); + AssertEqual(-0.0f, MathF.SinPi(-0.0f), 0.0f); + AssertEqual( 1.0f, MathF.SinPi( 0.5f), 0.0f); + AssertEqual(-1.0f, MathF.SinPi(-0.5f), 0.0f); + AssertEqual( 0.0f, MathF.SinPi( 1.0f), 0.0f); + AssertEqual(-0.0f, MathF.SinPi(-1.0f), 0.0f); + AssertEqual(-1.0f, MathF.SinPi( 1.5f), 0.0f); + AssertEqual( 1.0f, MathF.SinPi(-1.5f), 0.0f); + AssertEqual( 0.0f, MathF.SinPi( 2.0f), 0.0f); + AssertEqual(-0.0f, MathF.SinPi(-2.0f), 0.0f); + + AssertEqual(0.0f, MathF.SinPi(0.1234f) + MathF.SinPi(-0.1234f), 0.0f); + AssertEqual(0.0f, MathF.SinPi(0.6789f) + MathF.SinPi(-0.6789f), 0.0f); + AssertEqual(0.0f, MathF.SinPi(1.2345f) + MathF.SinPi(-1.2345f), 0.0f); + } + + [Fact] + public static void CosPi_Double_Precision() + { + AssertEqual( 1.0, Math.CosPi( 0.0), 0.0); + AssertEqual( 1.0, Math.CosPi(-0.0), 0.0); + AssertEqual( 0.0, Math.CosPi( 0.5), 0.0); + AssertEqual( 0.0, Math.CosPi(-0.5), 0.0); + AssertEqual(-1.0, Math.CosPi( 1.0), 0.0); + AssertEqual(-1.0, Math.CosPi(-1.0), 0.0); + AssertEqual( 0.0, Math.CosPi( 1.5), 0.0); + AssertEqual( 0.0, Math.CosPi(-1.5), 0.0); + AssertEqual( 1.0, Math.CosPi( 2.0), 0.0); + AssertEqual( 1.0, Math.CosPi(-2.0), 0.0); + + AssertEqual(0.0, Math.CosPi(0.1234) - Math.CosPi(-0.1234), 0.0); + AssertEqual(0.0, Math.CosPi(0.6789) - Math.CosPi(-0.6789), 0.0); + AssertEqual(0.0, Math.CosPi(1.2345) - Math.CosPi(-1.2345), 0.0); + } + + [Fact] + public static void CosPi_Float_Precision() + { + AssertEqual( 1.0f, MathF.CosPi( 0.0f), 0.0f); + AssertEqual( 1.0f, MathF.CosPi(-0.0f), 0.0f); + AssertEqual( 0.0f, MathF.CosPi( 0.5f), 0.0f); + AssertEqual( 0.0f, MathF.CosPi(-0.5f), 0.0f); + AssertEqual(-1.0f, MathF.CosPi( 1.0f), 0.0f); + AssertEqual(-1.0f, MathF.CosPi(-1.0f), 0.0f); + AssertEqual( 0.0f, MathF.CosPi( 1.5f), 0.0f); + AssertEqual( 0.0f, MathF.CosPi(-1.5f), 0.0f); + AssertEqual( 1.0f, MathF.CosPi( 2.0f), 0.0f); + AssertEqual( 1.0f, MathF.CosPi(-2.0f), 0.0f); + + AssertEqual(0.0f, MathF.CosPi(0.1234f) - MathF.CosPi(-0.1234f), 0.0f); + AssertEqual(0.0f, MathF.CosPi(0.6789f) - MathF.CosPi(-0.6789f), 0.0f); + AssertEqual(0.0f, MathF.CosPi(1.2345f) - MathF.CosPi(-1.2345f), 0.0f); + } + + [Fact] + public static void TanPi_Double_Precision() + { + AssertEqual( 0.0, Math.TanPi( 0.0), 0.0); + AssertEqual( -0.0, Math.TanPi(-0.0), 0.0); + AssertEqual(double.PositiveInfinity, Math.TanPi( 0.5), 0.0); + AssertEqual(double.NegativeInfinity, Math.TanPi(-0.5), 0.0); + AssertEqual( -0.0, Math.TanPi( 1.0), 0.0); + AssertEqual( 0.0, Math.TanPi(-1.0), 0.0); + AssertEqual(double.NegativeInfinity, Math.TanPi( 1.5), 0.0); + AssertEqual(double.PositiveInfinity, Math.TanPi(-1.5), 0.0); + AssertEqual( 0.0, Math.TanPi( 2.0), 0.0); + AssertEqual( -0.0, Math.TanPi(-2.0), 0.0); + + AssertEqual(0.0, Math.TanPi(0.1234) + Math.TanPi(-0.1234), 0.0); + AssertEqual(0.0, Math.TanPi(0.6789) + Math.TanPi(-0.6789), 0.0); + AssertEqual(0.0, Math.TanPi(1.2345) + Math.TanPi(-1.2345), 0.0); + } + + [Fact] + public static void TanPi_Float_Precision() + { + AssertEqual( 0.0f, MathF.TanPi( 0.0f), 0.0f); + AssertEqual( -0.0f, MathF.TanPi(-0.0f), 0.0f); + AssertEqual(float.PositiveInfinity, MathF.TanPi( 0.5f), 0.0f); + AssertEqual(float.NegativeInfinity, MathF.TanPi(-0.5f), 0.0f); + AssertEqual( -0.0f, MathF.TanPi( 1.0f), 0.0f); + AssertEqual( 0.0f, MathF.TanPi(-1.0f), 0.0f); + AssertEqual(float.NegativeInfinity, MathF.TanPi( 1.5f), 0.0f); + AssertEqual(float.PositiveInfinity, MathF.TanPi(-1.5f), 0.0f); + AssertEqual( 0.0f, MathF.TanPi( 2.0f), 0.0f); + AssertEqual( -0.0f, MathF.TanPi(-2.0f), 0.0f); + + AssertEqual(0.0f, MathF.TanPi(0.1234f) + MathF.TanPi(-0.1234f), 0.0f); + AssertEqual(0.0f, MathF.TanPi(0.6789f) + MathF.TanPi(-0.6789f), 0.0f); + AssertEqual(0.0f, MathF.TanPi(1.2345f) + MathF.TanPi(-1.2345f), 0.0f); + } + + [Theory] + [InlineData(0.1234)] + [InlineData(0.6789)] + [InlineData(1.2345)] + [InlineData(1.9876)] + public static void TriPi_Double_Correctness(double x) + { + AssertEqual(Math.Sin(x * Math.PI), Math.SinPi(x), CrossPlatformMachineEpsilonForEstimates); + AssertEqual(Math.Cos(x * Math.PI), Math.CosPi(x), CrossPlatformMachineEpsilonForEstimates); + AssertEqual(Math.Tan(x * Math.PI), Math.TanPi(x), CrossPlatformMachineEpsilonForEstimates); + } + + [Theory] + [InlineData(0.1234f)] + [InlineData(0.6789f)] + [InlineData(1.2345f)] + [InlineData(1.9876f)] + public static void TriPi_Float_Correctness(float x) + { + AssertEqual(MathF.Sin(x * MathF.PI), MathF.SinPi(x), (float)CrossPlatformMachineEpsilonForEstimates); + AssertEqual(MathF.Cos(x * MathF.PI), MathF.CosPi(x), (float)CrossPlatformMachineEpsilonForEstimates); + AssertEqual(MathF.Tan(x * MathF.PI), MathF.TanPi(x), (float)CrossPlatformMachineEpsilonForEstimates); + } + + [Fact] + public static void AsinPi_Double_Precision() + { + AssertEqual( 0.5, Math.AsinPi( 1.0), 0.0); + AssertEqual(-0.5, Math.AsinPi(-1.0), 0.0); + } + + [Fact] + public static void AsinPi_Float_Precision() + { + AssertEqual( 0.5f, MathF.AsinPi( 1.0f), 0.0f); + AssertEqual(-0.5f, MathF.AsinPi(-1.0f), 0.0f); + } + + [Fact] + public static void AcosPi_Double_Precision() + { + AssertEqual( 0.5, Math.AcosPi( 0.0), 0.0); + AssertEqual( 0.5, Math.AcosPi(-0.0), 0.0); + AssertEqual( 0.0, Math.AcosPi( 1.0), 0.0); + AssertEqual( 1.0, Math.AcosPi(-1.0), 0.0); + } + + [Fact] + public static void AcosPi_Float_Precision() + { + AssertEqual( 0.5f, MathF.AcosPi( 0.0f), 0.0f); + AssertEqual( 0.5f, MathF.AcosPi(-0.0f), 0.0f); + AssertEqual( 0.0f, MathF.AcosPi( 1.0f), 0.0f); + AssertEqual( 1.0f, MathF.AcosPi(-1.0f), 0.0f); + } + + [Fact] + public static void AtanPi_Double_Precision() + { + AssertEqual( 0.5, Math.AtanPi(double.PositiveInfinity), 0.0); + AssertEqual(-0.5, Math.AtanPi(double.NegativeInfinity), 0.0); + } + + [Fact] + public static void AtanPi_Float_Precision() + { + AssertEqual( 0.5f, MathF.AtanPi(float.PositiveInfinity), 0.0f); + AssertEqual(-0.5f, MathF.AtanPi(float.NegativeInfinity), 0.0f); + } + + [Theory] + [InlineData( 0.0, -0.0, 1.0)] + [InlineData(-0.0, -0.0, -1.0)] + [InlineData( 0.0, -1.0, 1.0)] + [InlineData(-0.0, -1.0, -1.0)] + [InlineData(-1.0, 0.0, -0.5)] + [InlineData(-1.0, -0.0, -0.5)] + [InlineData( 1.0, 0.0, 0.5)] + [InlineData( 1.0, -0.0, 0.5)] + [InlineData( 1.0, double.NegativeInfinity, 1.0)] + [InlineData(-1.0, double.NegativeInfinity, -1.0)] + [InlineData(double.PositiveInfinity, 1.0, 0.5)] + [InlineData(double.PositiveInfinity, -1.0, 0.5)] + [InlineData(double.NegativeInfinity, 1.0, -0.5)] + [InlineData(double.NegativeInfinity, -1.0, -0.5)] + [InlineData(double.PositiveInfinity, double.NegativeInfinity, 0.75)] + [InlineData(double.NegativeInfinity, double.NegativeInfinity, -0.75)] + [InlineData(double.PositiveInfinity, double.PositiveInfinity, 0.25)] + [InlineData(double.NegativeInfinity, double.PositiveInfinity, -0.25)] + public static void Atan2Pi_Double_Precision(double y, double x, double expected) + { + AssertEqual(expected, Math.Atan2Pi(y, x), 0.0); + } + + [Theory] + [InlineData( 0.0f, -0.0f, 1.0f)] + [InlineData(-0.0f, -0.0f, -1.0f)] + [InlineData( 0.0f, -1.0f, 1.0f)] + [InlineData(-0.0f, -1.0f, -1.0f)] + [InlineData(-1.0f, 0.0f, -0.5f)] + [InlineData(-1.0f, -0.0f, -0.5f)] + [InlineData( 1.0f, 0.0f, 0.5f)] + [InlineData( 1.0f, -0.0f, 0.5f)] + [InlineData( 1.0f, float.NegativeInfinity, 1.0f)] + [InlineData(-1.0f, float.NegativeInfinity, -1.0f)] + [InlineData(float.PositiveInfinity, 1.0f, 0.5f)] + [InlineData(float.PositiveInfinity, -1.0f, 0.5f)] + [InlineData(float.NegativeInfinity, 1.0f, -0.5f)] + [InlineData(float.NegativeInfinity, -1.0f, -0.5f)] + [InlineData(float.PositiveInfinity, float.NegativeInfinity, 0.75f)] + [InlineData(float.NegativeInfinity, float.NegativeInfinity, -0.75f)] + [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.25f)] + [InlineData(float.NegativeInfinity, float.PositiveInfinity, -0.25f)] + public static void Atan2Pi_Float_Precision(float y, float x, float expected) + { + AssertEqual(expected, MathF.Atan2Pi(y, x), 0.0f); + } } } diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index ba30ccf66a0aa9..56ab5e7c211f8d 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -2751,11 +2751,15 @@ public static partial class Math public static float Abs(float value) { throw null; } public static double Acos(double d) { throw null; } public static double Acosh(double d) { throw null; } + public static double AcosPi(double x) { throw null; } public static double Asin(double d) { throw null; } public static double Asinh(double d) { throw null; } + public static double AsinPi(double x) { throw null; } public static double Atan(double d) { throw null; } public static double Atan2(double y, double x) { throw null; } + public static double Atan2Pi(double y, double x) { throw null; } public static double Atanh(double d) { throw null; } + public static double AtanPi(double x) { throw null; } public static long BigMul(int a, int b) { throw null; } public static long BigMul(long a, long b, out long low) { throw null; } [System.CLSCompliantAttribute(false)] @@ -2786,6 +2790,7 @@ public static partial class Math public static double CopySign(double x, double y) { throw null; } public static double Cos(double d) { throw null; } public static double Cosh(double value) { throw null; } + public static double CosPi(double x) { throw null; } public static int DivRem(int a, int b, out int result) { throw null; } public static long DivRem(long a, long b, out long result) { throw null; } public static (byte Quotient, byte Remainder) DivRem(byte left, byte right) { throw null; } @@ -2875,9 +2880,11 @@ public static partial class Math public static double Sin(double a) { throw null; } public static (double Sin, double Cos) SinCos(double x) { throw null; } public static double Sinh(double value) { throw null; } + public static double SinPi(double x) { throw null; } public static double Sqrt(double d) { throw null; } public static double Tan(double a) { throw null; } public static double Tanh(double value) { throw null; } + public static double TanPi(double x) { throw null; } public static decimal Truncate(decimal d) { throw null; } public static double Truncate(double d) { throw null; } } @@ -2889,11 +2896,15 @@ public static partial class MathF public static float Abs(float x) { throw null; } public static float Acos(float x) { throw null; } public static float Acosh(float x) { throw null; } + public static float AcosPi(float x) { throw null; } public static float Asin(float x) { throw null; } public static float Asinh(float x) { throw null; } + public static float AsinPi(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 Atan2Pi(float y, float x) { throw null; } public static float Atanh(float x) { throw null; } + public static float AtanPi(float x) { throw null; } public static float BitDecrement(float x) { throw null; } public static float BitIncrement(float x) { throw null; } public static float Cbrt(float x) { throw null; } @@ -2901,6 +2912,7 @@ public static partial class MathF public static float CopySign(float x, float y) { throw null; } public static float Cos(float x) { throw null; } public static float Cosh(float x) { throw null; } + public static float CosPi(float x) { throw null; } public static float Exp(float x) { throw null; } public static float Floor(float x) { throw null; } public static float FusedMultiplyAdd(float x, float y, float z) { throw null; } @@ -2926,9 +2938,11 @@ public static partial class MathF public static float Sin(float x) { throw null; } public static (float Sin, float Cos) SinCos(float x) { throw null; } public static float Sinh(float x) { throw null; } + public static float SinPi(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 TanPi(float x) { throw null; } public static float Truncate(float x) { throw null; } } public partial class MemberAccessException : System.SystemException