From 0855da7ae4bc1a88cb1086be7285e7c1735972a8 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 22 Jun 2022 14:10:00 -0700 Subject: [PATCH] Exposing AcosPi, AsinPi, Atan2Pi, AtanPi, CosPi, SinPi, and TanPi for ITrigonometricFunctions (#71033) * Exposing AcosPi, AsinPi, Atan2Pi, AtanPi, CosPi, SinPi, and TanPi for ITrigonometricFunctions * Adding tests for AcosPi, AsinPi, Atan2Pi, AtanPi, CosPi, SinPi, and TanPi * Fixing the handling of AcosPi, AsinPi, and AtanPi tests on WASM/Unix --- .../src/System/Double.cs | 483 +++++++++++++++++- .../System.Private.CoreLib/src/System/Half.cs | 40 +- .../Numerics/ITrigonometricFunctions.cs | 66 ++- .../System/Runtime/InteropServices/NFloat.cs | 40 +- .../src/System/Single.cs | 400 ++++++++++++++- .../ref/System.Runtime.InteropServices.cs | 7 + .../Runtime/InteropServices/NFloatTests.cs | 326 +++++++++++- .../System.Runtime/ref/System.Runtime.cs | 28 + .../tests/System/DoubleTests.cs | 160 ++++++ .../System.Runtime/tests/System/HalfTests.cs | 197 ++++++- .../tests/System/SingleTests.cs | 159 ++++++ 11 files changed, 1817 insertions(+), 89 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index 3ad8e88c640eb..4bbced51cb342 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -1671,47 +1671,310 @@ static double NegativeN(double x, int n) /// public static double Acos(double x) => Math.Acos(x); + /// + public static double AcosPi(double x) + { + return Acos(x) / Pi; + } + /// public static double Asin(double x) => Math.Asin(x); + /// + public static double AsinPi(double x) + { + return Asin(x) / Pi; + } + /// public static double Atan(double x) => Math.Atan(x); /// public static double Atan2(double y, double x) => Math.Atan2(y, x); + /// + public static double Atan2Pi(double y, double x) + { + return Atan2(y, x) / Pi; + } + + /// + public static double AtanPi(double x) + { + return Atan(x) / Pi; + } + /// public static double Cos(double x) => Math.Cos(x); + /// + public static double CosPi(double x) + { + // This code is based on `cospi` from amd/aocl-libm-ose + // Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved. + // + // Licensed under the BSD 3-Clause "New" or "Revised" License + // See THIRD-PARTY-NOTICES.TXT for the full license text + + double result; + + if (IsFinite(x)) + { + double ax = Abs(x); + + if (ax < 4_503_599_627_370_496.0) // |x| < 2^52 + { + if (ax > 0.25) + { + long integral = (long)ax; + + double fractional = ax - integral; + double sign = long.IsOddInteger(integral) ? -1.0 : +1.0; + + if (fractional <= 0.25) + { + result = sign; + + if (fractional != 0.00) + { + result *= CosForIntervalPiBy4(fractional * Pi, 0.0); + } + } + else if (fractional <= 0.50) + { + if (fractional != 0.50) + { + result = sign * SinForIntervalPiBy4((0.5 - fractional) * Pi, 0.0); + } + else + { + result = 0.0; + } + } + else if (fractional <= 0.75) + { + result = -sign * SinForIntervalPiBy4((fractional - 0.5) * Pi, 0.0); + } + else + { + result = -sign * CosForIntervalPiBy4((1.0 - fractional) * Pi, 0.0); + } + } + else if (ax >= 6.103515625E-05) // |x| >= 2^-14 + { + result = CosForIntervalPiBy4(x * Pi, 0.0); + } + else if (ax >= 7.450580596923828E-09) // |x| >= 2^-27 + { + result = x * Pi; + result = 1.0 - (result * result * 0.5); + } + else + { + result = 1.0; + } + } + else if (ax < 9_007_199_254_740_992.0) // |x| < 2^53 + { + // x is an integer + long bits = BitConverter.DoubleToInt64Bits(ax); + result = long.IsOddInteger(bits) ? -1.0 : +1.0; + } + else + { + // x is an even integer + result = 1.0; + } + } + else + { + result = NaN; + } + + return result; + } + /// public static double Sin(double x) => Math.Sin(x); /// public static (double Sin, double Cos) SinCos(double x) => Math.SinCos(x); + /// + public static double SinPi(double x) + { + // This code is based on `sinpi` from amd/aocl-libm-ose + // Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved. + // + // Licensed under the BSD 3-Clause "New" or "Revised" License + // See THIRD-PARTY-NOTICES.TXT for the full license text + + double result; + + if (IsFinite(x)) + { + double ax = Abs(x); + + if (ax < 4_503_599_627_370_496.0) // |x| < 2^52 + { + if (ax > 0.25) + { + long integral = (long)ax; + + double fractional = ax - integral; + double sign = ((x > 0.0) ? +1.0 : -1.0) * (long.IsOddInteger(integral) ? -1.0 : +1.0); + + if (fractional <= 0.25) + { + if (fractional != 0.00) + { + result = sign * SinForIntervalPiBy4(fractional * Pi, 0.0); + } + else + { + result = x * 0.0; + } + } + else if (fractional <= 0.50) + { + result = sign; + + if (fractional != 0.50) + { + result *= CosForIntervalPiBy4((0.5 - fractional) * Pi, 0.0); + } + } + else if (fractional <= 0.75) + { + result = sign * CosForIntervalPiBy4((fractional - 0.5) * Pi, 0.0); + } + else + { + result = sign * SinForIntervalPiBy4((1.0 - fractional) * Pi, 0.0); + } + } + else if (ax >= 1.220703125E-4) // |x| >= 2^-13 + { + result = SinForIntervalPiBy4(x * Pi, 0.0); + } + else if (ax >= 7.450580596923828E-09) // |x| >= 2^-27 + { + result = x * Pi; + result -= result * (result * (result * (1.0 / 6.0))); + } + else + { + result = x * Pi; + } + } + else + { + // x is an integer + result = x * 0.0; + } + } + else + { + result = NaN; + } + + return result; + } + /// public static double Tan(double x) => Math.Tan(x); - // /// - // public static double AcosPi(double x) => Math.AcosPi(x); + /// + public static double TanPi(double x) + { + // This code is based on `tanpi` from amd/aocl-libm-ose + // Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved. + // + // Licensed under the BSD 3-Clause "New" or "Revised" License + // See THIRD-PARTY-NOTICES.TXT for the full license text - // /// - // public static double AsinPi(double x) => Math.AsinPi(x); + double result; - // /// - // public static double AtanPi(double x) => Math.AtanPi(x); + if (IsFinite(x)) + { + double ax = Abs(x); + double sign = (x > 0.0) ? +1.0 : -1.0; - // /// - // public static double Atan2Pi(double y, double x) => Math.Atan2Pi(y, x); + if (ax < 4_503_599_627_370_496.0) // |x| < 2^52 + { + if (ax > 0.25) + { + long integral = (long)ax; + double fractional = ax - integral; - // /// - // public static double CosPi(double x) => Math.CosPi(x); + if (fractional <= 0.25) + { + result = sign; - // /// - // public static double SinPi(double x) => Math.SinPi(x, y); + if (fractional != 0.00) + { + result *= TanForIntervalPiBy4(fractional * Pi, 0.0, isReciprocal: false); + } + else + { + result *= long.IsOddInteger(integral) ? -0.0 : +0.0; + } + } + else if (fractional <= 0.50) + { + result = sign; + + if (fractional != 0.50) + { + result *= -TanForIntervalPiBy4((0.5 - fractional) * Pi, 0.0, isReciprocal: true); + } + else + { + result *= long.IsOddInteger(integral) ? NegativeInfinity : PositiveInfinity; + } + } + else if (fractional <= 0.75) + { + result = +sign * TanForIntervalPiBy4((fractional - 0.5) * Pi, 0.0, isReciprocal: true); + } + else + { + result = -sign * TanForIntervalPiBy4((1.0 - fractional) * Pi, 0.0, isReciprocal: false); + } + } + else if (ax >= 6.103515625E-05) // |x| >= 2^-14 + { + result = TanForIntervalPiBy4(x * Pi, 0.0, isReciprocal: false); + } + else if (ax >= 7.450580596923828E-09) // |x| >= 2^-27 + { + result = x * Pi; + result += (result * (result * (result * (1.0 / 3.0)))); + } + else + { + result = x * Pi; + } + } + else if (ax < 9_007_199_254_740_992.0) // |x| < 2^53 + { + // x is an integer + long bits = BitConverter.DoubleToInt64Bits(ax); + result = sign * (long.IsOddInteger(bits) ? -0.0 : +0.0); + } + else + { + // x is an even integer + result = sign * 0.0; + } + } + else + { + result = NaN; + } - // /// - // public static double TanPi(double x) => Math.TanPi(x, y); + return result; + } // // IUnaryNegationOperators @@ -1726,5 +1989,197 @@ static double NegativeN(double x, int n) /// static double IUnaryPlusOperators.operator +(double value) => (double)(+value); + + // + // Helpers + // + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double CosForIntervalPiBy4(double x, double xTail) + { + // This code is based on `cos_piby4` from amd/aocl-libm-ose + // Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved. + // + // Licensed under the BSD 3-Clause "New" or "Revised" License + // See THIRD-PARTY-NOTICES.TXT for the full license text + + // Taylor series for cos(x) is: 1 - (x^2 / 2!) + (x^4 / 4!) - (x^6 / 6!) ... + // + // Then define f(xx) where xx = (x * x) + // and f(xx) = 1 - (xx / 2!) + (xx^2 / 4!) - (xx^3 / 6!) ... + // + // We use a minimax approximation of (f(xx) - 1 + (xx / 2)) / (xx * xx) + // because this produces an expansion in even powers of x. + // + // If xTail is non-zero, we subtract a correction term g(x, xTail) = (x * xTail) + // to the result, where g(x, xTail) is an approximation to sin(x) * sin(xTail) + // + // This is valid because xTail is tiny relative to x. + + const double C1 = +0.41666666666666665390037E-1; // approx: +1 / 4! + const double C2 = -0.13888888888887398280412E-2; // approx: -1 / 6! + const double C3 = +0.248015872987670414957399E-4; // approx: +1 / 8! + const double C4 = -0.275573172723441909470836E-6; // approx: -1 / 10! + const double C5 = +0.208761463822329611076335E-8; // approx: +1 / 12! + const double C6 = -0.113826398067944859590880E-10; // approx: -1 / 14! + + double xx = x * x; + + double tmp1 = 0.5 * xx; + double tmp2 = 1.0 - tmp1; + + double result = C6; + + result = (result * xx) + C5; + result = (result * xx) + C4; + result = (result * xx) + C3; + result = (result * xx) + C2; + result = (result * xx) + C1; + + result *= (xx * xx); + result += 1.0 - tmp2 - tmp1 - (x * xTail); + result += tmp2; + + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double SinForIntervalPiBy4(double x, double xTail) + { + // This code is based on `sin_piby4` from amd/aocl-libm-ose + // Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved. + // + // Licensed under the BSD 3-Clause "New" or "Revised" License + // See THIRD-PARTY-NOTICES.TXT for the full license text + + // Taylor series for sin(x) is x - (x^3 / 3!) + (x^5 / 5!) - (x^7 / 7!) ... + // Which can be expressed as x * (1 - (x^2 / 3!) + (x^4 /5!) - (x^6 /7!) ...) + // + // Then define f(xx) where xx = (x * x) + // and f(xx) = 1 - (xx / 3!) + (xx^2 / 5!) - (xx^3 / 7!) ... + // + // We use a minimax approximation of (f(xx) - 1) / xx + // because this produces an expansion in even powers of x. + // + // If xTail is non-zero, we add a correction term g(x, xTail) = (1 - xx / 2) * xTail + // to the result, where g(x, xTail) is an approximation to cos(x) * sin(xTail) + // + // This is valid because xTail is tiny relative to x. + + const double C1 = -0.166666666666666646259241729; // approx: -1 / 3! + const double C2 = +0.833333333333095043065222816E-2; // approx: +1 / 5! + const double C3 = -0.19841269836761125688538679E-3; // approx: -1 / 7! + const double C4 = +0.275573161037288022676895908448E-5; // approx: +1 / 9! + const double C5 = -0.25051132068021699772257377197E-7; // approx: -1 / 11! + const double C6 = +0.159181443044859136852668200E-9; // approx: +1 / 13! + + double xx = x * x; + double xxx = xx * x; + + double result = C6; + + result = (result * xx) + C5; + result = (result * xx) + C4; + result = (result * xx) + C3; + result = (result * xx) + C2; + + if (xTail == 0.0) + { + result = (xx * result) + C1; + result = (xxx * result) + x; + } + else + { + result = x - ((xx * ((0.5 * xTail) - (xxx * result))) - xTail - (xxx * C1)); + } + + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double TanForIntervalPiBy4(double x, double xTail, bool isReciprocal) + { + // This code is based on `tan_piby4` from amd/aocl-libm-ose + // Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved. + // + // Licensed under the BSD 3-Clause "New" or "Revised" License + // See THIRD-PARTY-NOTICES.TXT for the full license text + + // In order to maintain relative precision transform using the identity: + // tan((pi / 4) - x) = (1 - tan(x)) / (1 + tan(x)) for arguments close to (pi / 4). + // + // Similarly use tan(x - (pi / 4)) = (tan(x) - 1) / (tan(x) + 1) close to (-pi / 4). + + const double PiBy4Head = 7.85398163397448278999E-01; + const double PiBy4Tail = 3.06161699786838240164E-17; + + int transform = 0; + + if (x > +0.68) + { + transform = 1; + x = (PiBy4Head - x) + (PiBy4Tail - xTail); + xTail = 0.0; + } + else if (x < -0.68) + { + transform = -1; + x = (PiBy4Head + x) + (PiBy4Tail + xTail); + xTail = 0.0; + } + + // Core Remez [2, 3] approximation to tan(x + xTail) on the interval [0, 0.68]. + + double tmp1 = (x * x) + (2.0 * x * xTail); + + double denominator = -0.232371494088563558304549252913E-3; + denominator = +0.260656620398645407524064091208E-1 + (denominator * tmp1); + denominator = -0.515658515729031149329237816945E+0 + (denominator * tmp1); + denominator = +0.111713747927937668539901657944E+1 + (denominator * tmp1); + + double numerator = +0.224044448537022097264602535574E-3; + numerator = -0.229345080057565662883358588111E-1 + (numerator * tmp1); + numerator = +0.372379159759792203640806338901E+0 + (numerator * tmp1); + + double tmp2 = x * tmp1; + tmp2 *= numerator / denominator; + tmp2 += xTail; + + // Reconstruct tan(x) in the transformed case + + double result = x + tmp2; + + if (transform != 0) + { + if (isReciprocal) + { + result = (transform * (2 * result / (result - 1))) - 1.0; + } + else + { + result = transform * (1.0 - (2 * result / (1 + result))); + } + } + else if (isReciprocal) + { + // Compute -1.0 / (x + tmp2) accurately + + ulong bits = BitConverter.DoubleToUInt64Bits(result); + bits &= 0xFFFFFFFF00000000; + + double z1 = BitConverter.UInt64BitsToDouble(bits); + double z2 = tmp2 - (z1 - x); + + double reciprocal = -1.0 / result; + + bits = BitConverter.DoubleToUInt64Bits(reciprocal); + bits &= 0xFFFFFFFF00000000; + + double reciprocalHead = BitConverter.UInt64BitsToDouble(bits); + result = reciprocalHead + (reciprocal * (1.0 + (reciprocalHead * z1) + (reciprocalHead * z2))); + } + + return result; + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs index 2dde194b91668..f4ec37bc4c4e0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Half.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs @@ -1828,18 +1828,33 @@ private static bool TryConvertTo(Half value, [NotNullWhen(true)] out TOt /// public static Half Acos(Half x) => (Half)MathF.Acos((float)x); + /// + public static Half AcosPi(Half x) => (Half)float.AcosPi((float)x); + /// public static Half Asin(Half x) => (Half)MathF.Asin((float)x); + /// + public static Half AsinPi(Half x) => (Half)float.AsinPi((float)x); + /// public static Half Atan(Half x) => (Half)MathF.Atan((float)x); /// public static Half Atan2(Half y, Half x) => (Half)MathF.Atan2((float)y, (float)x); + /// + public static Half Atan2Pi(Half y, Half x) => (Half)float.Atan2Pi((float)y, (float)x); + + /// + public static Half AtanPi(Half x) => (Half)float.AtanPi((float)x); + /// public static Half Cos(Half x) => (Half)MathF.Cos((float)x); + /// + public static Half CosPi(Half x) => (Half)float.CosPi((float)x); + /// public static Half Sin(Half x) => (Half)MathF.Sin((float)x); @@ -1850,29 +1865,14 @@ public static (Half Sin, Half Cos) SinCos(Half x) return ((Half)sin, (Half)cos); } + /// + public static Half SinPi(Half x) => (Half)float.SinPi((float)x); + /// public static Half Tan(Half x) => (Half)MathF.Tan((float)x); - // /// - // public static Half AcosPi(Half x) => (Half)MathF.AcosPi((float)x); - - // /// - // public static Half AsinPi(Half x) => (Half)MathF.AsinPi((float)x); - - // /// - // public static Half AtanPi(Half x) => (Half)MathF.AtanPi((float)x); - - // /// - // public static Half Atan2Pi(Half y, Half x) => (Half)MathF.Atan2Pi((float)y, (float)x); - - // /// - // public static Half CosPi(Half x) => (Half)MathF.CosPi((float)x); - - // /// - // public static Half SinPi(Half x) => (Half)MathF.SinPi((float)x, (float)y); - - // /// - // public static Half TanPi(Half x) => (Half)MathF.TanPi((float)x, (float)y); + /// + public static Half TanPi(Half x) => (Half)float.TanPi((float)x); // // IUnaryNegationOperators diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/ITrigonometricFunctions.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/ITrigonometricFunctions.cs index 9a073e4eb80e1..4ba25bebbfd9d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/ITrigonometricFunctions.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/ITrigonometricFunctions.cs @@ -9,53 +9,95 @@ public interface ITrigonometricFunctions where TSelf : ITrigonometricFunctions, INumberBase { /// Computes the arc-cosine of a value. - /// The value, in radians, whose arc-cosine is to be computed. + /// The value whose arc-cosine is to be computed. /// The arc-cosine of . + /// This computes arccos(x) in the interval [+0, +π] radians. static abstract TSelf Acos(TSelf x); + /// Computes the arc-cosine of a value and divides the result by pi. + /// The value whose arc-cosine is to be computed. + /// The arc-cosine of , divided by pi. + /// This computes arccos(x) / π in the interval [-0.5, +0.5]. + static abstract TSelf AcosPi(TSelf x); + /// Computes the arc-sine of a value. - /// The value, in radians, whose arc-sine is to be computed. + /// The value whose arc-sine is to be computed. /// The arc-sine of . + /// This computes arcsin(x) in the interval [-π / 2, +π / 2] radians. static abstract TSelf Asin(TSelf x); + /// Computes the arc-sine of a value and divides the result by pi. + /// The value whose arc-sine is to be computed. + /// The arc-sine of , divided by pi. + /// This computes arcsin(x) / π in the interval [-0.5, +0.5]. + static abstract TSelf AsinPi(TSelf x); + /// Computes the arc-tangent of a value. - /// The value, in radians, whose arc-tangent is to be computed. + /// The value whose arc-tangent is to be computed. /// The arc-tangent of . + /// This computes arctan(x) in the interval [-π / 2, +π / 2] radians. static abstract TSelf Atan(TSelf x); - /// Computes the arc-tangent of the quotient of two values. + /// Computes the arc-tangent for the quotient of two values. /// The y-coordinate of a point. /// The x-coordinate of a point. /// The arc-tangent of divided-by . + /// This computes arctan(y / x) in the interval [-π, +π] radians. static abstract TSelf Atan2(TSelf y, TSelf x); + /// Computes the arc-tangent for the quotient of two values and divides the result by pi. + /// The y-coordinate of a point. + /// The x-coordinate of a point. + /// The arc-tangent of divided-by , divided by pi. + /// This computes arctan(y / x) / π in the interval [-1, +1]. + static abstract TSelf Atan2Pi(TSelf y, TSelf x); + + /// Computes the arc-tangent of a value and divides the result by pi. + /// The value whose arc-tangent is to be computed. + /// The arc-tangent of , divided by pi. + /// This computes arctan(x) / π in the interval [-0.5, +0.5]. + static abstract TSelf AtanPi(TSelf x); + /// Computes the cosine of a value. /// The value, in radians, whose cosine is to be computed. /// The cosine of . + /// This computes cos(x). static abstract TSelf Cos(TSelf x); + /// Computes the cosine of a value that has been multipled by pi. + /// The value, in half-revolutions, whose cosine is to be computed. + /// The cosine of multiplied-by pi. + /// This computes cos(x * π). + static abstract TSelf CosPi(TSelf x); + /// Computes the sine of a value. /// The value, in radians, whose sine is to be computed. /// The sine of . + /// This computes sin(x). static abstract TSelf Sin(TSelf x); /// Computes the sine and cosine of a value. /// The value, in radians, whose sine and cosine are to be computed. /// The sine and cosine of . + /// This computes (sin(x), cos(x)). static abstract (TSelf Sin, TSelf Cos) SinCos(TSelf x); + /// Computes the sine of a value that has been multipled by pi. + /// The value, in half-revolutions, that is multipled by pi before computing its sine. + /// The sine of multiplied-by pi. + /// This computes sin(x * π). + static abstract TSelf SinPi(TSelf x); + /// Computes the tangent of a value. /// The value, in radians, whose tangent is to be computed. /// The tangent of . + /// This computes tan(x). static abstract TSelf Tan(TSelf x); - // The following methods are approved but not yet implemented in the libraries - // * static abstract TSelf AcosPi(TSelf x); - // * static abstract TSelf AsinPi(TSelf x); - // * static abstract TSelf AtanPi(TSelf x); - // * static abstract TSelf Atan2Pi(TSelf y, TSelf x); - // * static abstract TSelf CosPi(TSelf x); - // * static abstract TSelf SinPi(TSelf x); - // * static abstract TSelf TanPi(TSelf x); + /// Computes the tangent of a value that has been multipled by pi. + /// The value, in half-revolutions, that is multipled by pi before computing its tangent. + /// The tangent of multiplied-by pi. + /// This computes tan(x * π). + static abstract TSelf TanPi(TSelf x); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs index b3f4213a29b1a..942fe97fe644b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs @@ -1733,18 +1733,33 @@ private static bool TryConvertTo(NFloat value, [NotNullWhen(true)] out T /// public static NFloat Acos(NFloat x) => new NFloat(NativeType.Acos(x._value)); + /// + public static NFloat AcosPi(NFloat x) => new NFloat(NativeType.AcosPi(x._value)); + /// public static NFloat Asin(NFloat x) => new NFloat(NativeType.Asin(x._value)); + /// + public static NFloat AsinPi(NFloat x) => new NFloat(NativeType.AsinPi(x._value)); + /// public static NFloat Atan(NFloat x) => new NFloat(NativeType.Atan(x._value)); /// public static NFloat Atan2(NFloat y, NFloat x) => new NFloat(NativeType.Atan2(y._value, x._value)); + /// + public static NFloat Atan2Pi(NFloat y, NFloat x) => new NFloat(NativeType.Atan2Pi(y._value, x._value)); + + /// + public static NFloat AtanPi(NFloat x) => new NFloat(NativeType.AtanPi(x._value)); + /// public static NFloat Cos(NFloat x) => new NFloat(NativeType.Cos(x._value)); + /// + public static NFloat CosPi(NFloat x) => new NFloat(NativeType.CosPi(x._value)); + /// public static NFloat Sin(NFloat x) => new NFloat(NativeType.Sin(x._value)); @@ -1755,28 +1770,13 @@ public static (NFloat Sin, NFloat Cos) SinCos(NFloat x) return (new NFloat(sin), new NFloat(cos)); } + /// + public static NFloat SinPi(NFloat x) => new NFloat(NativeType.SinPi(x._value)); + /// public static NFloat Tan(NFloat x) => new NFloat(NativeType.Tan(x._value)); - // /// - // public static NFloat AcosPi(NFloat x) => new NFloat(NativeType.AcosPi(x._value)); - - // /// - // public static NFloat AsinPi(NFloat x) => new NFloat(NativeType.AsinPi(x._value)); - - // /// - // public static NFloat AtanPi(NFloat x) => new NFloat(NativeType.AtanPi(x._value)); - - // /// - // public static NFloat Atan2Pi(NFloat y, NFloat x) => new NFloat(NativeType.Atan2Pi(y._value, x._value)); - - // /// - // public static NFloat CosPi(NFloat x) => new NFloat(NativeType.CosPi(x._value)); - - // /// - // public static NFloat SinPi(NFloat x) => new NFloat(NativeType.SinPi(x._value, y._value)); - - // /// - // public static NFloat TanPi(NFloat x) => new NFloat(NativeType.TanPi(x._value, y._value)); + /// + public static NFloat TanPi(NFloat x) => new NFloat(NativeType.TanPi(x._value)); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index 2d45346b5c9ed..b71cc590f2f1d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -1548,47 +1548,310 @@ static float NegativeN(float x, int n) /// public static float Acos(float x) => MathF.Acos(x); + /// + public static float AcosPi(float x) + { + return Acos(x) / Pi; + } + /// public static float Asin(float x) => MathF.Asin(x); + /// + public static float AsinPi(float x) + { + return Asin(x) / Pi; + } + /// public static float Atan(float x) => MathF.Atan(x); /// public static float Atan2(float y, float x) => MathF.Atan2(y, x); + /// + public static float Atan2Pi(float y, float x) + { + return Atan2(y, x) / Pi; + } + + /// + public static float AtanPi(float x) + { + return Atan(x) / Pi; + } + /// public static float Cos(float x) => MathF.Cos(x); + /// + public static float CosPi(float x) + { + // This code is based on `cospif` from amd/aocl-libm-ose + // Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved. + // + // Licensed under the BSD 3-Clause "New" or "Revised" License + // See THIRD-PARTY-NOTICES.TXT for the full license text + + float result; + + if (IsFinite(x)) + { + float ax = Abs(x); + + if (ax < 8_388_608.0f) // |x| < 2^23 + { + if (ax > 0.25f) + { + int integral = (int)ax; + + float fractional = ax - integral; + float sign = int.IsOddInteger(integral) ? -1.0f : +1.0f; + + if (fractional <= 0.25f) + { + result = sign; + + if (fractional != 0.00f) + { + result *= CosForIntervalPiBy4(fractional * Pi); + } + } + else if (fractional <= 0.50f) + { + if (fractional != 0.50f) + { + result = sign * SinForIntervalPiBy4((0.5f - fractional) * Pi); + } + else + { + result = 0.0f; + } + } + else if (fractional <= 0.75) + { + result = -sign * SinForIntervalPiBy4((fractional - 0.5f) * Pi); + } + else + { + result = -sign * CosForIntervalPiBy4((1.0f - fractional) * Pi); + } + } + else if (ax >= 7.8125E-3f) // |x| >= 2^-7 + { + result = CosForIntervalPiBy4(x * Pi); + } + else if (ax >= 1.22070313E-4f) // |x| >= 2^-13 + { + result = x * Pi; + result = 1.0f - (result * result * 0.5f); + } + else + { + result = 1.0f; + } + } + else if (ax < 16_777_216.0f) // |x| < 2^24 + { + // x is an integer + int bits = BitConverter.SingleToInt32Bits(ax); + result = int.IsOddInteger(bits) ? -1.0f : +1.0f; + } + else + { + // x is an even integer + result = 1.0f; + } + } + else + { + result = NaN; + } + + return result; + } + /// public static float Sin(float x) => MathF.Sin(x); /// public static (float Sin, float Cos) SinCos(float x) => MathF.SinCos(x); + /// + public static float SinPi(float x) + { + // This code is based on `sinpif` from amd/aocl-libm-ose + // Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved. + // + // Licensed under the BSD 3-Clause "New" or "Revised" License + // See THIRD-PARTY-NOTICES.TXT for the full license text + + float result; + + if (IsFinite(x)) + { + float ax = Abs(x); + + if (ax < 8_388_608.0f) // |x| < 2^23 + { + if (ax > 0.25f) + { + int integral = (int)ax; + + float fractional = ax - integral; + float sign = ((x > 0.0f) ? +1.0f : -1.0f) * (int.IsOddInteger(integral) ? -1.0f : +1.0f); + + if (fractional <= 0.25f) + { + if (fractional != 0.00f) + { + result = sign * SinForIntervalPiBy4(fractional * Pi); + } + else + { + result = x * 0.0f; + } + } + else if (fractional <= 0.50f) + { + result = sign; + + if (fractional != 0.50f) + { + result *= CosForIntervalPiBy4((0.5f - fractional) * Pi); + } + } + else if (fractional <= 0.75f) + { + result = sign * CosForIntervalPiBy4((fractional - 0.5f) * Pi); + } + else + { + result = sign * SinForIntervalPiBy4((1.0f - fractional) * Pi); + } + } + else if (ax >= 7.8125E-3f) // |x| >= 2^-7 + { + result = SinForIntervalPiBy4(x * Pi); + } + else if (ax >= 1.22070313E-4f) // |x| >= 2^-13 + { + result = x * Pi; + result -= result * (result * (result * (1.0f / 6.0f))); + } + else + { + result = x * Pi; + } + } + else + { + // x is an integer + result = x * 0.0f; + } + } + else + { + result = NaN; + } + + return result; + } + /// public static float Tan(float x) => MathF.Tan(x); - // /// - // public static float AcosPi(float x) => MathF.AcosPi(x); - - // /// - // public static float AsinPi(float x) => MathF.AsinPi(x); + /// + public static float TanPi(float x) + { + // This code is based on `tanpif` from amd/aocl-libm-ose + // Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved. + // + // Licensed under the BSD 3-Clause "New" or "Revised" License + // See THIRD-PARTY-NOTICES.TXT for the full license text - // /// - // public static float AtanPi(float x) => MathF.AtanPi(x); + float result; - // /// - // public static float Atan2Pi(float y, float x) => MathF.Atan2Pi(y, x); + if (IsFinite(x)) + { + float ax = Abs(x); + float sign = (x > 0.0f) ? +1.0f : -1.0f; - // /// - // public static float CosPi(float x) => MathF.CosPi(x); + if (ax < 8_388_608.0f) // |x| < 2^23 + { + if (ax > 0.25f) + { + int integral = (int)ax; + float fractional = ax - integral; - // /// - // public static float SinPi(float x) => MathF.SinPi(x, y); + if (fractional <= 0.25f) + { + result = sign; + + if (fractional != 0.00f) + { + result *= TanForIntervalPiBy4(fractional * Pi, isReciprocal: false); + } + else + { + result *= int.IsOddInteger(integral) ? -0.0f : +0.0f; + } + } + else if (fractional <= 0.50f) + { + result = sign; + + if (fractional != 0.50f) + { + result *= -TanForIntervalPiBy4((0.5f - fractional) * Pi, isReciprocal: true); + } + else + { + result *= int.IsOddInteger(integral) ? NegativeInfinity : PositiveInfinity; + } + } + else if (fractional <= 0.75f) + { + result = +sign * TanForIntervalPiBy4((fractional - 0.5f) * Pi, isReciprocal: true); + } + else + { + result = -sign * TanForIntervalPiBy4((1.0f - fractional) * Pi, isReciprocal: false); + } + } + else if (ax >= 7.8125E-3f) // |x| >= 2^-7 + { + result = TanForIntervalPiBy4(x * Pi, isReciprocal: false); + } + else if (ax >= 1.22070313E-4f) // |x| >= 2^-13 + { + result = x * Pi; + result += (result * (result * (result * (1.0f / 3.0f)))); + } + else + { + result = x * Pi; + } + } + else if (ax < 16_777_216) // |x| < 2^24 + { + // x is an integer + int bits = BitConverter.SingleToInt32Bits(ax); + result = sign * (int.IsOddInteger(bits) ? -0.0f : +0.0f); + } + else + { + // x is an even integer + result = sign * 0.0f; + } + } + else + { + result = NaN; + } - // /// - // public static float TanPi(float x) => MathF.TanPi(x, y); + return result; + } // // IUnaryNegationOperators @@ -1603,5 +1866,112 @@ static float NegativeN(float x, int n) /// static float IUnaryPlusOperators.operator +(float value) => (float)(+value); + + // + // Helpers + // + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float CosForIntervalPiBy4(float x) + { + // This code is based on `cos_piby4` from amd/aocl-libm-ose + // Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved. + // + // Licensed under the BSD 3-Clause "New" or "Revised" License + // See THIRD-PARTY-NOTICES.TXT for the full license text + + // Taylor series for cos(x) is: 1 - (x^2 / 2!) + (x^4 / 4!) - (x^6 / 6!) ... + // + // Then define f(xx) where xx = (x * x) + // and f(xx) = 1 - (xx / 2!) + (xx^2 / 4!) - (xx^3 / 6!) ... + // + // We use a minimax approximation of (f(xx) - 1 + (xx / 2)) / (xx * xx) + // because this produces an expansion in even powers of x. + + const double C1 = +0.41666666666666665390037E-1; // approx: +1 / 4! + const double C2 = -0.13888888888887398280412E-2; // approx: -1 / 6! + const double C3 = +0.248015872987670414957399E-4; // approx: +1 / 8! + const double C4 = -0.275573172723441909470836E-6; // approx: -1 / 10! + + double xx = x * x; + double result = C4; + + result = (result * xx) + C3; + result = (result * xx) + C2; + result = (result * xx) + C1; + + result *= xx * xx; + result += 1.0 - (0.5 * xx); + + return (float)result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float SinForIntervalPiBy4(float x) + { + // This code is based on `sin_piby4` from amd/aocl-libm-ose + // Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved. + // + // Licensed under the BSD 3-Clause "New" or "Revised" License + // See THIRD-PARTY-NOTICES.TXT for the full license text + + // Taylor series for sin(x) is x - (x^3 / 3!) + (x^5 / 5!) - (x^7 / 7!) ... + // Which can be expressed as x * (1 - (x^2 / 3!) + (x^4 /5!) - (x^6 /7!) ...) + // + // Then define f(xx) where xx = (x * x) + // and f(xx) = 1 - (xx / 3!) + (xx^2 / 5!) - (xx^3 / 7!) ... + // + // We use a minimax approximation of (f(xx) - 1) / xx + // because this produces an expansion in even powers of x. + + const double C1 = -0.166666666666666646259241729; // approx: -1 / 3! + const double C2 = +0.833333333333095043065222816E-2; // approx: +1 / 5! + const double C3 = -0.19841269836761125688538679E-3; // approx: -1 / 7! + const double C4 = +0.275573161037288022676895908448E-5; // approx: +1 / 9! + + double xx = x * x; + double result = C4; + + result = (result * xx) + C3; + result = (result * xx) + C2; + result = (result * xx) + C1; + + result *= x * xx; + result += x; + + return (float)result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float TanForIntervalPiBy4(float x, bool isReciprocal) + { + // This code is based on `tan_piby4` from amd/aocl-libm-ose + // Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved. + // + // Licensed under the BSD 3-Clause "New" or "Revised" License + // See THIRD-PARTY-NOTICES.TXT for the full license text + + // Core Remez [1, 2] approximation to tan(x) on the interval [0, pi / 4]. + + double xx = x * x; + + double denominator = +0.1844239256901656082986661E-1; + denominator = -0.51396505478854532132342E+0 + (denominator * xx); + denominator = +0.115588821434688393452299E+1 + (denominator * xx); + + double numerator = -0.172032480471481694693109E-1; + numerator = 0.385296071263995406715129E+0 + (numerator * xx); + + double result = x * xx; + result *= numerator / denominator; + result += x; + + if (isReciprocal) + { + result = -1.0 / result; + } + + return (float)result; + } } } diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index 75eca17032a4a..ba4ccb2687d38 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -838,11 +838,15 @@ public static void Free(void* ptr) { } public static System.Runtime.InteropServices.NFloat Abs(System.Runtime.InteropServices.NFloat value) { throw null; } public static System.Runtime.InteropServices.NFloat Acos(System.Runtime.InteropServices.NFloat x) { throw null; } public static System.Runtime.InteropServices.NFloat Acosh(System.Runtime.InteropServices.NFloat x) { throw null; } + public static System.Runtime.InteropServices.NFloat AcosPi(System.Runtime.InteropServices.NFloat x) { throw null; } public static System.Runtime.InteropServices.NFloat Asin(System.Runtime.InteropServices.NFloat x) { throw null; } public static System.Runtime.InteropServices.NFloat Asinh(System.Runtime.InteropServices.NFloat x) { throw null; } + public static System.Runtime.InteropServices.NFloat AsinPi(System.Runtime.InteropServices.NFloat x) { throw null; } public static System.Runtime.InteropServices.NFloat Atan(System.Runtime.InteropServices.NFloat x) { throw null; } public static System.Runtime.InteropServices.NFloat Atan2(System.Runtime.InteropServices.NFloat y, System.Runtime.InteropServices.NFloat x) { throw null; } + public static System.Runtime.InteropServices.NFloat Atan2Pi(System.Runtime.InteropServices.NFloat y, System.Runtime.InteropServices.NFloat x) { throw null; } public static System.Runtime.InteropServices.NFloat Atanh(System.Runtime.InteropServices.NFloat x) { throw null; } + public static System.Runtime.InteropServices.NFloat AtanPi(System.Runtime.InteropServices.NFloat x) { throw null; } public static System.Runtime.InteropServices.NFloat BitDecrement(System.Runtime.InteropServices.NFloat x) { throw null; } public static System.Runtime.InteropServices.NFloat BitIncrement(System.Runtime.InteropServices.NFloat x) { throw null; } public static System.Runtime.InteropServices.NFloat Cbrt(System.Runtime.InteropServices.NFloat x) { throw null; } @@ -853,6 +857,7 @@ public static void Free(void* ptr) { } public static System.Runtime.InteropServices.NFloat CopySign(System.Runtime.InteropServices.NFloat value, System.Runtime.InteropServices.NFloat sign) { throw null; } public static System.Runtime.InteropServices.NFloat Cos(System.Runtime.InteropServices.NFloat x) { throw null; } public static System.Runtime.InteropServices.NFloat Cosh(System.Runtime.InteropServices.NFloat x) { throw null; } + public static System.Runtime.InteropServices.NFloat CosPi(System.Runtime.InteropServices.NFloat x) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } public bool Equals(System.Runtime.InteropServices.NFloat other) { throw null; } public static System.Runtime.InteropServices.NFloat Exp(System.Runtime.InteropServices.NFloat x) { throw null; } @@ -995,6 +1000,7 @@ public static void Free(void* ptr) { } public static System.Runtime.InteropServices.NFloat Sin(System.Runtime.InteropServices.NFloat x) { throw null; } public static (System.Runtime.InteropServices.NFloat Sin, System.Runtime.InteropServices.NFloat Cos) SinCos(System.Runtime.InteropServices.NFloat x) { throw null; } public static System.Runtime.InteropServices.NFloat Sinh(System.Runtime.InteropServices.NFloat x) { throw null; } + public static System.Runtime.InteropServices.NFloat SinPi(System.Runtime.InteropServices.NFloat x) { throw null; } public static System.Runtime.InteropServices.NFloat Sqrt(System.Runtime.InteropServices.NFloat x) { throw null; } static System.Runtime.InteropServices.NFloat System.Numerics.IAdditionOperators.operator checked +(System.Runtime.InteropServices.NFloat left, System.Runtime.InteropServices.NFloat right) { throw null; } static System.Runtime.InteropServices.NFloat System.Numerics.IBitwiseOperators.operator &(System.Runtime.InteropServices.NFloat left, System.Runtime.InteropServices.NFloat right) { throw null; } @@ -1027,6 +1033,7 @@ public static void Free(void* ptr) { } static System.Runtime.InteropServices.NFloat System.Numerics.IUnaryNegationOperators.operator checked -(System.Runtime.InteropServices.NFloat value) { throw null; } public static System.Runtime.InteropServices.NFloat Tan(System.Runtime.InteropServices.NFloat x) { throw null; } public static System.Runtime.InteropServices.NFloat Tanh(System.Runtime.InteropServices.NFloat x) { throw null; } + public static System.Runtime.InteropServices.NFloat TanPi(System.Runtime.InteropServices.NFloat x) { throw null; } public override string ToString() { throw null; } public string ToString(System.IFormatProvider? provider) { throw null; } public string ToString([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] string? format) { throw null; } diff --git a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/NFloatTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/NFloatTests.cs index fb12b52eebb92..ec31ffcaaff51 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/NFloatTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/NFloatTests.cs @@ -1474,7 +1474,7 @@ public static void Log10P1Test32(float value, float expectedResult, float allowe [InlineData(10.0f, 0.693147181f, 10.0239939f, CrossPlatformMachineEpsilon32 * 100)] // y: (ln(2)) [InlineData(10.0f, 0.707106781f, 10.0249688f, CrossPlatformMachineEpsilon32 * 100)] // y: (1 / sqrt(2)) [InlineData(10.0f, 0.785398163f, 10.0307951f, CrossPlatformMachineEpsilon32 * 100)] // y: (pi / 4) - [InlineData(10.0f, 1.0f, 10.0498756f, CrossPlatformMachineEpsilon32 * 100)] // + [InlineData(10.0f, 1.0f, 10.0498756f, CrossPlatformMachineEpsilon32 * 100)] // [InlineData(10.0f, 1.12837917f, 10.0634606f, CrossPlatformMachineEpsilon32 * 100)] // y: (2 / sqrt(pi)) [InlineData(10.0f, 1.41421356f, 10.0995049f, CrossPlatformMachineEpsilon32 * 100)] // y: (sqrt(2)) [InlineData(10.0f, 1.44269504f, 10.1035325f, CrossPlatformMachineEpsilon32 * 100)] // y: (log2(e)) @@ -1545,7 +1545,7 @@ public static void Hypot32(float x, float y, float expectedResult, float allowed [InlineData(-0.0f, 2, 0.0f, 0.0f)] [InlineData(-0.0f, 3, -0.0f, 0.0f)] [InlineData(-0.0f, 4, 0.0f, 0.0f)] - [InlineData(-0.0f, 5, -0.0f, 0.0f)] + [InlineData(-0.0f, 5, -0.0f, 0.0f)] [InlineData( float.NaN, -5, float.NaN, 0.0f)] [InlineData( float.NaN, -4, float.NaN, 0.0f)] [InlineData( float.NaN, -3, float.NaN, 0.0f)] @@ -1606,6 +1606,165 @@ public static void Root32(float x, int n, float expectedResult, float allowedVar AssertExtensions.Equal(expectedResult, NFloat.Root(x, n), allowedVariance); } + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is32BitProcess))] + [InlineData( float.NaN, float.NaN, 0.0f)] + [InlineData( 1.0f, 0.0f, 0.0f)] + [InlineData( 0.540302306f, 0.318309886f, CrossPlatformMachineEpsilon32)] + [InlineData( 0.204957194f, 0.434294482f, CrossPlatformMachineEpsilon32)] + [InlineData( 0.0f, 0.5f, CrossPlatformMachineEpsilon32)] // This should be exact, but has an issue on WASM/Unix + [InlineData(-0.416146837f, 0.636619772f, CrossPlatformMachineEpsilon32)] + [InlineData(-0.570233249f, 0.693147181f, CrossPlatformMachineEpsilon32)] + [InlineData(-0.605699867f, 0.707106781f, CrossPlatformMachineEpsilon32)] + [InlineData(-0.781211892f, 0.785398163f, CrossPlatformMachineEpsilon32)] + [InlineData(-1.0f, 1.0f, CrossPlatformMachineEpsilon32)] // This should be exact, but has an issue on WASM/Unix + [InlineData(-0.919764995f, 0.871620833f, CrossPlatformMachineEpsilon32)] + [InlineData(-0.266255342f, 0.585786438f, CrossPlatformMachineEpsilon32)] + [InlineData(-0.179057946f, 0.557304959f, CrossPlatformMachineEpsilon32)] + [InlineData( 0.220584041f, 0.429203673f, CrossPlatformMachineEpsilon32)] + [InlineData( 0.581195664f, 0.302585093f, CrossPlatformMachineEpsilon32)] + [InlineData(-0.633255651f, 0.718281828f, CrossPlatformMachineEpsilon32)] + [InlineData(-0.902685362f, 0.858407346f, CrossPlatformMachineEpsilon32)] + public static void AcosPiTest32(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, (float)NFloat.AcosPi(value), allowedVariance); + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is32BitProcess))] + [InlineData( float.NaN, float.NaN, 0.0f)] + [InlineData( 0.0f, 0.0f, 0.0f)] + [InlineData( 0.841470985f, 0.318309886f, CrossPlatformMachineEpsilon32)] + [InlineData( 0.978770938f, 0.434294482f, CrossPlatformMachineEpsilon32)] + [InlineData( 1.0f, 0.5f, CrossPlatformMachineEpsilon32)] // This should be exact, but has an issue on WASM/Unix + [InlineData( 0.909297427f, 0.363380228f, CrossPlatformMachineEpsilon32)] + [InlineData( 0.821482831f, 0.306852819f, CrossPlatformMachineEpsilon32)] + [InlineData( 0.795693202f, 0.292893219f, CrossPlatformMachineEpsilon32)] + [InlineData( 0.624265953f, 0.214601837f, CrossPlatformMachineEpsilon32)] + [InlineData(-0.392469559f, -0.128379167f, CrossPlatformMachineEpsilon32)] + [InlineData(-0.963902533f, -0.414213562f, CrossPlatformMachineEpsilon32)] + [InlineData(-0.983838529f, -0.442695041f, CrossPlatformMachineEpsilon32)] + [InlineData(-0.975367972f, -0.429203673f, CrossPlatformMachineEpsilon32)] + [InlineData( 0.813763848f, 0.302585093f, CrossPlatformMachineEpsilon32)] + [InlineData( 0.773942685f, 0.281718172f, CrossPlatformMachineEpsilon32)] + [InlineData(-0.430301217f, -0.141592654f, CrossPlatformMachineEpsilon32)] + public static void AsinPiTest32(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(-expectedResult, (float)NFloat.AsinPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, (float)NFloat.AsinPi(+value), allowedVariance); + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is32BitProcess))] + [InlineData( float.NaN, float.NaN, 0.0f)] + [InlineData( 0.0f, 0.0f, 0.0f)] + [InlineData( 1.55740773f, 0.318309886f, CrossPlatformMachineEpsilon32)] + [InlineData( 4.77548954f, 0.434294482f, CrossPlatformMachineEpsilon32)] + [InlineData( float.PositiveInfinity, 0.5f, CrossPlatformMachineEpsilon32)] // This should be exact, but has an issue on WASM/Unix + [InlineData(-2.18503986f, -0.363380228f, CrossPlatformMachineEpsilon32)] + [InlineData(-1.44060844f, -0.306852819f, CrossPlatformMachineEpsilon32)] + [InlineData(-1.31367571f, -0.292893219f, CrossPlatformMachineEpsilon32)] + [InlineData(-0.79909940f, -0.214601837f, CrossPlatformMachineEpsilon32)] + [InlineData( 0.42670634f, 0.128379167f, CrossPlatformMachineEpsilon32)] + [InlineData( 3.62021857f, 0.414213562f, CrossPlatformMachineEpsilon32)] + [InlineData( 5.49452594f, 0.442695041f, CrossPlatformMachineEpsilon32)] + [InlineData(-4.42175222f, -0.429203673f, CrossPlatformMachineEpsilon32)] + [InlineData( 1.40015471f, 0.302585093f, CrossPlatformMachineEpsilon32)] + [InlineData(-1.22216467f, -0.281718172f, CrossPlatformMachineEpsilon32)] + [InlineData( 0.476690146f, 0.141592654f, CrossPlatformMachineEpsilon32)] + public static void AtanPiTest32(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(-expectedResult, (float)NFloat.AtanPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, (float)NFloat.AtanPi(+value), allowedVariance); + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is32BitProcess))] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 1.0f, 0.0f)] + [InlineData(0.318309886f, 0.540302306f, CrossPlatformMachineEpsilon32)] // value: (1 / pi) + [InlineData(0.434294482f, 0.204957194f, CrossPlatformMachineEpsilon32)] // value: (log10(e)) + [InlineData(0.5f, 0.0f, 0.0f)] + [InlineData(0.636619772f, -0.416146837f, CrossPlatformMachineEpsilon32)] // value: (2 / pi) + [InlineData(0.693147181f, -0.570233249f, CrossPlatformMachineEpsilon32)] // value: (ln(2)) + [InlineData(0.707106781f, -0.605699867f, CrossPlatformMachineEpsilon32)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, -0.781211892f, CrossPlatformMachineEpsilon32)] // value: (pi / 4) + [InlineData(1.0f, -1.0f, 0.0f)] + [InlineData(1.12837917f, -0.919764995f, CrossPlatformMachineEpsilon32)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, -0.266255342f, CrossPlatformMachineEpsilon32)] // value: (sqrt(2)) + [InlineData(1.44269504f, -0.179057946f, CrossPlatformMachineEpsilon32)] // value: (log2(e)) + [InlineData(1.5f, 0.0f, 0.0f)] + [InlineData(1.57079633f, 0.220584041f, CrossPlatformMachineEpsilon32)] // value: (pi / 2) + [InlineData(2.0f, 1.0f, 0.0f)] + [InlineData(2.30258509f, 0.581195664f, CrossPlatformMachineEpsilon32)] // value: (ln(10)) + [InlineData(2.5f, 0.0f, 0.0f)] + [InlineData(2.71828183f, -0.633255651f, CrossPlatformMachineEpsilon32)] // value: (e) + [InlineData(3.0f, -1.0f, 0.0f)] + [InlineData(3.14159265f, -0.902685362f, CrossPlatformMachineEpsilon32)] // value: (pi) + [InlineData(3.5f, 0.0f, 0.0f)] + [InlineData(float.PositiveInfinity, float.NaN, 0.0f)] + public static void CosPiTest32(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(+expectedResult, (float)NFloat.CosPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, (float)NFloat.CosPi(+value), allowedVariance); + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is32BitProcess))] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 0.841470985f, CrossPlatformMachineEpsilon32)] // value: (1 / pi) + [InlineData(0.434294482f, 0.978770938f, CrossPlatformMachineEpsilon32)] // value: (log10(e)) + [InlineData(0.5f, 1.0f, 0.0f)] + [InlineData(0.636619772f, 0.909297427f, CrossPlatformMachineEpsilon32)] // value: (2 / pi) + [InlineData(0.693147181f, 0.821482831f, CrossPlatformMachineEpsilon32)] // value: (ln(2)) + [InlineData(0.707106781f, 0.795693202f, CrossPlatformMachineEpsilon32)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 0.624265953f, CrossPlatformMachineEpsilon32)] // value: (pi / 4) + [InlineData(1.0f, 0.0f, 0.0f)] + [InlineData(1.12837917f, -0.392469559f, CrossPlatformMachineEpsilon32)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, -0.963902533f, CrossPlatformMachineEpsilon32)] // value: (sqrt(2)) + [InlineData(1.44269504f, -0.983838529f, CrossPlatformMachineEpsilon32)] // value: (log2(e)) + [InlineData(1.5f, -1.0f, 0.0f)] + [InlineData(1.57079633f, -0.975367972f, CrossPlatformMachineEpsilon32)] // value: (pi / 2) + [InlineData(2.0f, 0.0f, 0.0f)] + [InlineData(2.30258509f, 0.813763848f, CrossPlatformMachineEpsilon32)] // value: (ln(10)) + [InlineData(2.5f, 1.0f, 0.0f)] + [InlineData(2.71828183f, 0.773942685f, CrossPlatformMachineEpsilon32)] // value: (e) + [InlineData(3.0f, 0.0f, 0.0f)] + [InlineData(3.14159265f, -0.430301217f, CrossPlatformMachineEpsilon32)] // value: (pi) + [InlineData(3.5f, -1.0f, 0.0f)] + [InlineData(float.PositiveInfinity, float.NaN, 0.0f)] + public static void SinPiTest32(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(-expectedResult, (float)NFloat.SinPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, (float)NFloat.SinPi(+value), allowedVariance); + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is32BitProcess))] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 1.55740772f, CrossPlatformMachineEpsilon32 * 10)] // value: (1 / pi) + [InlineData(0.434294482f, 4.77548954f, CrossPlatformMachineEpsilon32 * 10)] // value: (log10(e)) + [InlineData(0.5f, float.PositiveInfinity, 0.0f)] + [InlineData(0.636619772f, -2.18503986f, CrossPlatformMachineEpsilon32 * 10)] // value: (2 / pi) + [InlineData(0.693147181f, -1.44060844f, CrossPlatformMachineEpsilon32 * 10)] // value: (ln(2)) + [InlineData(0.707106781f, -1.31367571f, CrossPlatformMachineEpsilon32 * 10)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, -0.799099398f, CrossPlatformMachineEpsilon32)] // value: (pi / 4) + [InlineData(1.0f, -0.0f, 0.0f)] + [InlineData(1.12837917f, 0.426706344f, CrossPlatformMachineEpsilon32)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 3.62021857f, CrossPlatformMachineEpsilon32 * 10)] // value: (sqrt(2)) + [InlineData(1.44269504f, 5.49452594f, CrossPlatformMachineEpsilon32 * 10)] // value: (log2(e)) + [InlineData(1.5f, float.NegativeInfinity, 0.0f)] + [InlineData(1.57079633f, -4.42175222f, CrossPlatformMachineEpsilon32 * 10)] // value: (pi / 2) + [InlineData(2.0f, 0.0f, 0.0f)] + [InlineData(2.30258509f, 1.40015471f, CrossPlatformMachineEpsilon32 * 10)] // value: (ln(10)) + [InlineData(2.5f, float.PositiveInfinity, 0.0f)] + [InlineData(2.71828183f, -1.22216467f, CrossPlatformMachineEpsilon32 * 10)] // value: (e) + [InlineData(3.0f, -0.0f, 0.0f)] + [InlineData(3.14159265f, 0.476690146f, CrossPlatformMachineEpsilon32)] // value: (pi) + [InlineData(3.5f, float.NegativeInfinity, 0.0f)] + [InlineData(float.PositiveInfinity, float.NaN, 0.0f)] + public static void TanPiTest32(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(-expectedResult, (float)NFloat.TanPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, (float)NFloat.TanPi(+value), allowedVariance); + } + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))] [InlineData( double.NegativeInfinity, -1.0, 0.0)] [InlineData(-3.1415926535897932, -0.95678608173622775, CrossPlatformMachineEpsilon64)] // value: -(pi) @@ -1958,7 +2117,7 @@ public static void Log10P1Test64(double value, double expectedResult, double all [InlineData(10.0, 0.69314718055994531, 10.023993865417028, CrossPlatformMachineEpsilon64 * 100)] // y: (ln(2)) [InlineData(10.0, 0.70710678118654752, 10.024968827881711, CrossPlatformMachineEpsilon64 * 100)] // y: (1 / sqrt(2)) [InlineData(10.0, 0.78539816339744831, 10.030795096853892, CrossPlatformMachineEpsilon64 * 100)] // y: (pi / 4) - [InlineData(10.0, 1.0, 10.049875621120890, CrossPlatformMachineEpsilon64 * 100)] // + [InlineData(10.0, 1.0, 10.049875621120890, CrossPlatformMachineEpsilon64 * 100)] // [InlineData(10.0, 1.1283791670955126, 10.063460614755501, CrossPlatformMachineEpsilon64 * 100)] // y: (2 / sqrt(pi)) [InlineData(10.0, 1.4142135623730950, 10.099504938362078, CrossPlatformMachineEpsilon64 * 100)] // y: (sqrt(2)) [InlineData(10.0, 1.4426950408889634, 10.103532500121213, CrossPlatformMachineEpsilon64 * 100)] // y: (log2(e)) @@ -2029,7 +2188,7 @@ public static void Hypot64(double x, double y, double expectedResult, double all [InlineData(-0.0, 2, 0.0, 0.0)] [InlineData(-0.0, 3, -0.0, 0.0)] [InlineData(-0.0, 4, 0.0, 0.0)] - [InlineData(-0.0, 5, -0.0, 0.0)] + [InlineData(-0.0, 5, -0.0, 0.0)] [InlineData( double.NaN, -5, double.NaN, 0.0)] [InlineData( double.NaN, -4, double.NaN, 0.0)] [InlineData( double.NaN, -3, double.NaN, 0.0)] @@ -2089,5 +2248,164 @@ public static void Root64(double x, int n, double expectedResult, double allowed { AssertExtensions.Equal(expectedResult, NFloat.Root((NFloat)x, n), allowedVariance); } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))] + [InlineData( double.NaN, double.NaN, 0.0)] + [InlineData( 1.0, 0.0, 0.0)] + [InlineData( 0.54030230586813972, 0.31830988618379067, CrossPlatformMachineEpsilon64)] + [InlineData( 0.20495719432643395, 0.43429448190325183, CrossPlatformMachineEpsilon64)] + [InlineData( 0.0, 0.5, 0.0)] + [InlineData(-0.41614683654714239, 0.63661977236758134, CrossPlatformMachineEpsilon64)] + [InlineData(-0.57023324876887755, 0.69314718055994531, CrossPlatformMachineEpsilon64)] + [InlineData(-0.60569986707881343, 0.70710678118654752, CrossPlatformMachineEpsilon64)] + [InlineData(-0.78121189211048819, 0.78539816339744831, CrossPlatformMachineEpsilon64)] + [InlineData(-1.0, 1.0, 0.0)] + [InlineData(-0.91976499476851874, 0.87162083290448743, CrossPlatformMachineEpsilon64)] + [InlineData(-0.26625534204141549, 0.58578643762690495, CrossPlatformMachineEpsilon64)] + [InlineData(-0.17905794598427576, 0.55730495911103659, CrossPlatformMachineEpsilon64)] + [InlineData( 0.22058404074969809, 0.42920367320510338, CrossPlatformMachineEpsilon64)] + [InlineData( 0.58119566361426737, 0.30258509299404568, CrossPlatformMachineEpsilon64)] + [InlineData(-0.63325565131482003, 0.71828182845904523, CrossPlatformMachineEpsilon64)] + [InlineData(-0.90268536193307107, 0.85840734641020676, CrossPlatformMachineEpsilon64)] + public static void AcosPiTest64(double value, double expectedResult, double allowedVariance) + { + AssertExtensions.Equal(expectedResult, NFloat.AcosPi((NFloat)(value)), allowedVariance); + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))] + [InlineData( double.NaN, double.NaN, 0.0)] + [InlineData( 0.0, 0.0, 0.0)] + [InlineData( 0.84147098480789651, 0.31830988618379067, CrossPlatformMachineEpsilon64)] + [InlineData( 0.97877093770393305, 0.43429448190325183, CrossPlatformMachineEpsilon64)] + [InlineData( 1.0, 0.5, 0.0)] + [InlineData( 0.90929742682568170, 0.36338022763241866, CrossPlatformMachineEpsilon64)] + [InlineData( 0.82148283122563883, 0.30685281944005469, CrossPlatformMachineEpsilon64)] + [InlineData( 0.79569320156748087, 0.29289321881345248, CrossPlatformMachineEpsilon64)] + [InlineData( 0.62426595263969903, 0.21460183660255169, CrossPlatformMachineEpsilon64)] + [InlineData(-0.39246955856278420, -0.12837916709551257, CrossPlatformMachineEpsilon64)] + [InlineData(-0.96390253284987733, -0.41421356237309505, CrossPlatformMachineEpsilon64)] + [InlineData(-0.98383852942436249, -0.44269504088896341, CrossPlatformMachineEpsilon64)] + [InlineData(-0.97536797208363139, -0.42920367320510338, CrossPlatformMachineEpsilon64)] + [InlineData( 0.81376384817462330, 0.30258509299404568, CrossPlatformMachineEpsilon64)] + [InlineData( 0.77394268526670828, 0.28171817154095476, CrossPlatformMachineEpsilon64)] + [InlineData(-0.43030121700009227, -0.14159265358979324, CrossPlatformMachineEpsilon64)] + public static void AsinPiTest64(double value, double expectedResult, double allowedVariance) + { + AssertExtensions.Equal(-expectedResult, NFloat.AsinPi((NFloat)(-value)), allowedVariance); + AssertExtensions.Equal(+expectedResult, NFloat.AsinPi((NFloat)(+value)), allowedVariance); + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))] + [InlineData( double.NaN, double.NaN, 0.0)] + [InlineData( 0.0, 0.0, 0.0)] + [InlineData( 1.5574077246549022, 0.31830988618379067, CrossPlatformMachineEpsilon64)] + [InlineData( 4.7754895402454188, 0.43429448190325183, CrossPlatformMachineEpsilon64)] + [InlineData( double.PositiveInfinity, 0.5, 0.0)] + [InlineData(-2.1850398632615190, -0.36338022763241866, CrossPlatformMachineEpsilon64)] + [InlineData(-1.4406084404920341, -0.30685281944005469, CrossPlatformMachineEpsilon64)] + [InlineData(-1.3136757077477542, -0.29289321881345248, CrossPlatformMachineEpsilon64)] + [InlineData(-0.79909939792801821, -0.21460183660255169, CrossPlatformMachineEpsilon64)] + [InlineData( 0.42670634433261806, 0.12837916709551257, CrossPlatformMachineEpsilon64)] + [InlineData( 3.6202185671074506, 0.41421356237309505, CrossPlatformMachineEpsilon64)] + [InlineData( 5.4945259425167300, 0.44269504088896341, CrossPlatformMachineEpsilon64)] + [InlineData(-4.4217522209161288, -0.42920367320510338, CrossPlatformMachineEpsilon64)] + [InlineData( 1.4001547140150527, 0.30258509299404568, CrossPlatformMachineEpsilon64)] + [InlineData(-1.2221646718190066, -0.28171817154095476, CrossPlatformMachineEpsilon64)] + [InlineData( 0.47669014603118892, 0.14159265358979324, CrossPlatformMachineEpsilon64)] + public static void AtanPiTest64(double value, double expectedResult, double allowedVariance) + { + AssertExtensions.Equal(-expectedResult, NFloat.AtanPi((NFloat)(-value)), allowedVariance); + AssertExtensions.Equal(+expectedResult, NFloat.AtanPi((NFloat)(+value)), allowedVariance); + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))] + [InlineData(double.NaN, double.NaN, 0.0)] + [InlineData(0.0, 1.0, 0.0)] + [InlineData(0.31830988618379067, 0.54030230586813972, CrossPlatformMachineEpsilon64)] // value: (1 / pi) + [InlineData(0.43429448190325183, 0.20495719432643395, CrossPlatformMachineEpsilon64)] // value: (log10(e)) + [InlineData(0.5, 0.0, 0.0)] + [InlineData(0.63661977236758134, -0.41614683654714239, CrossPlatformMachineEpsilon64)] // value: (2 / pi) + [InlineData(0.69314718055994531, -0.57023324876887755, CrossPlatformMachineEpsilon64)] // value: (ln(2)) + [InlineData(0.70710678118654752, -0.60569986707881343, CrossPlatformMachineEpsilon64)] // value: (1 / sqrt(2)) + [InlineData(0.78539816339744831, -0.78121189211048819, CrossPlatformMachineEpsilon64)] // value: (pi / 4) + [InlineData(1.0, -1.0, 0.0)] + [InlineData(1.1283791670955126, -0.91976499476851874, CrossPlatformMachineEpsilon64)] // value: (2 / sqrt(pi)) + [InlineData(1.4142135623730950, -0.26625534204141549, CrossPlatformMachineEpsilon64)] // value: (sqrt(2)) + [InlineData(1.4426950408889634, -0.17905794598427576, CrossPlatformMachineEpsilon64)] // value: (log2(e)) + [InlineData(1.5, 0.0, 0.0)] + [InlineData(1.5707963267948966, 0.22058404074969809, CrossPlatformMachineEpsilon64)] // value: (pi / 2) + [InlineData(2.0, 1.0, 0.0)] + [InlineData(2.3025850929940457, 0.58119566361426737, CrossPlatformMachineEpsilon64)] // value: (ln(10)) + [InlineData(2.5, 0.0, 0.0)] + [InlineData(2.7182818284590452, -0.63325565131482003, CrossPlatformMachineEpsilon64)] // value: (e) + [InlineData(3.0, -1.0, 0.0)] + [InlineData(3.1415926535897932, -0.90268536193307107, CrossPlatformMachineEpsilon64)] // value: (pi) + [InlineData(3.5, 0.0, 0.0)] + [InlineData(double.PositiveInfinity, double.NaN, 0.0)] + public static void CosPiTest64(double value, double expectedResult, double allowedVariance) + { + AssertExtensions.Equal(+expectedResult, NFloat.CosPi((NFloat)(-value)), allowedVariance); + AssertExtensions.Equal(+expectedResult, NFloat.CosPi((NFloat)(+value)), allowedVariance); + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))] + [InlineData(double.NaN, double.NaN, 0.0)] + [InlineData(0.0, 0.0, 0.0)] + [InlineData(0.31830988618379067, 0.84147098480789651, CrossPlatformMachineEpsilon64)] // value: (1 / pi) + [InlineData(0.43429448190325183, 0.97877093770393305, CrossPlatformMachineEpsilon64)] // value: (log10(e)) + [InlineData(0.5, 1.0, 0.0)] + [InlineData(0.63661977236758134, 0.90929742682568170, CrossPlatformMachineEpsilon64)] // value: (2 / pi) + [InlineData(0.69314718055994531, 0.82148283122563883, CrossPlatformMachineEpsilon64)] // value: (ln(2)) + [InlineData(0.70710678118654752, 0.79569320156748087, CrossPlatformMachineEpsilon64)] // value: (1 / sqrt(2)) + [InlineData(0.78539816339744831, 0.62426595263969903, CrossPlatformMachineEpsilon64)] // value: (pi / 4) + [InlineData(1.0, 0.0, 0.0)] + [InlineData(1.1283791670955126, -0.39246955856278420, CrossPlatformMachineEpsilon64)] // value: (2 / sqrt(pi)) + [InlineData(1.4142135623730950, -0.96390253284987733, CrossPlatformMachineEpsilon64)] // value: (sqrt(2)) + [InlineData(1.4426950408889634, -0.98383852942436249, CrossPlatformMachineEpsilon64)] // value: (log2(e)) + [InlineData(1.5, -1.0, 0.0)] + [InlineData(1.5707963267948966, -0.97536797208363139, CrossPlatformMachineEpsilon64)] // value: (pi / 2) + [InlineData(2.0, 0.0, 0.0)] + [InlineData(2.3025850929940457, 0.81376384817462330, CrossPlatformMachineEpsilon64)] // value: (ln(10)) + [InlineData(2.5, 1.0, 0.0)] + [InlineData(2.7182818284590452, 0.77394268526670828, CrossPlatformMachineEpsilon64)] // value: (e) + [InlineData(3.0, 0.0, 0.0)] + [InlineData(3.1415926535897932, -0.43030121700009227, CrossPlatformMachineEpsilon64)] // value: (pi) + [InlineData(3.5, -1.0, 0.0)] + [InlineData(double.PositiveInfinity, double.NaN, 0.0)] + public static void SinPiTest64(double value, double expectedResult, double allowedVariance) + { + AssertExtensions.Equal(-expectedResult, NFloat.SinPi((NFloat)(-value)), allowedVariance); + AssertExtensions.Equal(+expectedResult, NFloat.SinPi((NFloat)(+value)), allowedVariance); + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))] + [InlineData(double.NaN, double.NaN, 0.0)] + [InlineData(0.0, 0.0, 0.0)] + [InlineData(0.31830988618379067, 1.5574077246549022, CrossPlatformMachineEpsilon64 * 10)] // value: (1 / pi) + [InlineData(0.43429448190325183, 4.7754895402454188, CrossPlatformMachineEpsilon64 * 10)] // value: (log10(e)) + [InlineData(0.5, double.PositiveInfinity, 0.0)] + [InlineData(0.63661977236758134, -2.1850398632615190, CrossPlatformMachineEpsilon64 * 10)] // value: (2 / pi) + [InlineData(0.69314718055994531, -1.4406084404920341, CrossPlatformMachineEpsilon64 * 10)] // value: (ln(2)) + [InlineData(0.70710678118654752, -1.3136757077477542, CrossPlatformMachineEpsilon64 * 10)] // value: (1 / sqrt(2)) + [InlineData(0.78539816339744831, -0.79909939792801821, CrossPlatformMachineEpsilon64)] // value: (pi / 4) + [InlineData(1.0, -0.0, 0.0)] + [InlineData(1.1283791670955126, 0.42670634433261806, CrossPlatformMachineEpsilon64)] // value: (2 / sqrt(pi)) + [InlineData(1.4142135623730950, 3.6202185671074506, CrossPlatformMachineEpsilon64 * 10)] // value: (sqrt(2)) + [InlineData(1.4426950408889634, 5.4945259425167300, CrossPlatformMachineEpsilon64 * 10)] // value: (log2(e)) + [InlineData(1.5, double.NegativeInfinity, 0.0)] + [InlineData(1.5707963267948966, -4.4217522209161288, CrossPlatformMachineEpsilon64 * 10)] // value: (pi / 2) + [InlineData(2.0, 0.0, 0.0)] + [InlineData(2.3025850929940457, 1.4001547140150527, CrossPlatformMachineEpsilon64 * 10)] // value: (ln(10)) + [InlineData(2.5, double.PositiveInfinity, 0.0)] + [InlineData(2.7182818284590452, -1.2221646718190066, CrossPlatformMachineEpsilon64 * 10)] // value: (e) + [InlineData(3.0, -0.0, 0.0)] + [InlineData(3.1415926535897932, 0.47669014603118892, CrossPlatformMachineEpsilon64)] // value: (pi) + [InlineData(3.5, double.NegativeInfinity, 0.0)] + [InlineData(double.PositiveInfinity, double.NaN, 0.0)] + public static void TanPiTest64(double value, double expectedResult, double allowedVariance) + { + AssertExtensions.Equal(-expectedResult, NFloat.TanPi((NFloat)(-value)), allowedVariance); + AssertExtensions.Equal(+expectedResult, NFloat.TanPi((NFloat)(+value)), allowedVariance); + } } } diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index a26dbe17f6f67..4d592b8f1f628 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -2115,11 +2115,15 @@ public DivideByZeroException(string? message, System.Exception? innerException) public static double Abs(double value) { throw null; } public static double Acos(double x) { throw null; } public static double Acosh(double x) { throw null; } + public static double AcosPi(double x) { throw null; } public static double Asin(double x) { throw null; } public static double Asinh(double x) { throw null; } + public static double AsinPi(double x) { throw null; } public static double Atan(double x) { 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 x) { throw null; } + public static double AtanPi(double x) { throw null; } public static double BitDecrement(double x) { throw null; } public static double BitIncrement(double x) { throw null; } public static double Cbrt(double x) { throw null; } @@ -2130,6 +2134,7 @@ public DivideByZeroException(string? message, System.Exception? innerException) public static double CopySign(double value, double sign) { throw null; } public static double Cos(double x) { throw null; } public static double Cosh(double x) { throw null; } + public static double CosPi(double x) { throw null; } public bool Equals(double obj) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } public static double Exp(double x) { throw null; } @@ -2199,6 +2204,7 @@ public DivideByZeroException(string? message, System.Exception? innerException) public static double Sin(double x) { throw null; } public static (double Sin, double Cos) SinCos(double x) { throw null; } public static double Sinh(double x) { throw null; } + public static double SinPi(double x) { throw null; } public static double Sqrt(double x) { throw null; } bool System.IConvertible.ToBoolean(System.IFormatProvider? provider) { throw null; } byte System.IConvertible.ToByte(System.IFormatProvider? provider) { throw null; } @@ -2248,6 +2254,7 @@ public DivideByZeroException(string? message, System.Exception? innerException) static double System.Numerics.IUnaryPlusOperators.operator +(double value) { throw null; } public static double Tan(double x) { throw null; } public static double Tanh(double x) { throw null; } + public static double TanPi(double x) { throw null; } public override string ToString() { throw null; } public string ToString(System.IFormatProvider? provider) { throw null; } public string ToString([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] string? format) { throw null; } @@ -2738,11 +2745,15 @@ public GopherStyleUriParser() { } public static System.Half Abs(System.Half value) { throw null; } public static System.Half Acos(System.Half x) { throw null; } public static System.Half Acosh(System.Half x) { throw null; } + public static System.Half AcosPi(System.Half x) { throw null; } public static System.Half Asin(System.Half x) { throw null; } public static System.Half Asinh(System.Half x) { throw null; } + public static System.Half AsinPi(System.Half x) { throw null; } public static System.Half Atan(System.Half x) { throw null; } public static System.Half Atan2(System.Half y, System.Half x) { throw null; } + public static System.Half Atan2Pi(System.Half y, System.Half x) { throw null; } public static System.Half Atanh(System.Half x) { throw null; } + public static System.Half AtanPi(System.Half x) { throw null; } public static System.Half BitDecrement(System.Half x) { throw null; } public static System.Half BitIncrement(System.Half x) { throw null; } public static System.Half Cbrt(System.Half x) { throw null; } @@ -2753,6 +2764,7 @@ public GopherStyleUriParser() { } public static System.Half CopySign(System.Half value, System.Half sign) { throw null; } public static System.Half Cos(System.Half x) { throw null; } public static System.Half Cosh(System.Half x) { throw null; } + public static System.Half CosPi(System.Half x) { throw null; } public bool Equals(System.Half other) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } public static System.Half Exp(System.Half x) { throw null; } @@ -2890,6 +2902,7 @@ public GopherStyleUriParser() { } public static System.Half Sin(System.Half x) { throw null; } public static (System.Half Sin, System.Half Cos) SinCos(System.Half x) { throw null; } public static System.Half Sinh(System.Half x) { throw null; } + public static System.Half SinPi(System.Half x) { throw null; } public static System.Half Sqrt(System.Half x) { throw null; } static System.Half System.Numerics.IBitwiseOperators.operator &(System.Half left, System.Half right) { throw null; } static System.Half System.Numerics.IBitwiseOperators.operator |(System.Half left, System.Half right) { throw null; } @@ -2915,6 +2928,7 @@ public GopherStyleUriParser() { } static bool System.Numerics.INumberBase.TryConvertToTruncating(System.Half value, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out TOther result) { throw null; } public static System.Half Tan(System.Half x) { throw null; } public static System.Half Tanh(System.Half x) { throw null; } + public static System.Half TanPi(System.Half x) { throw null; } public override string ToString() { throw null; } public string ToString(System.IFormatProvider? provider) { throw null; } public string ToString([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] string? format) { throw null; } @@ -4710,11 +4724,15 @@ public SerializableAttribute() { } public static float Abs(float value) { 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; } @@ -4725,6 +4743,7 @@ public SerializableAttribute() { } public static float CopySign(float value, float sign) { 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 override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } public bool Equals(float obj) { throw null; } public static float Exp(float x) { throw null; } @@ -4794,6 +4813,7 @@ public SerializableAttribute() { } 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; } bool System.IConvertible.ToBoolean(System.IFormatProvider? provider) { throw null; } byte System.IConvertible.ToByte(System.IFormatProvider? provider) { throw null; } @@ -4843,6 +4863,7 @@ public SerializableAttribute() { } static float System.Numerics.IUnaryPlusOperators.operator +(float value) { 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 override string ToString() { throw null; } public string ToString(System.IFormatProvider? provider) { throw null; } public string ToString([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] string? format) { throw null; } @@ -10544,13 +10565,20 @@ public partial interface ISubtractionOperators where TSe public partial interface ITrigonometricFunctions where TSelf : System.Numerics.ITrigonometricFunctions, System.Numerics.INumberBase { static abstract TSelf Acos(TSelf x); + static abstract TSelf AcosPi(TSelf x); static abstract TSelf Asin(TSelf x); + static abstract TSelf AsinPi(TSelf x); static abstract TSelf Atan(TSelf x); static abstract TSelf Atan2(TSelf y, TSelf x); + static abstract TSelf Atan2Pi(TSelf y, TSelf x); + static abstract TSelf AtanPi(TSelf x); static abstract TSelf Cos(TSelf x); + static abstract TSelf CosPi(TSelf x); static abstract TSelf Sin(TSelf x); static abstract (TSelf Sin, TSelf Cos) SinCos(TSelf x); + static abstract TSelf SinPi(TSelf x); static abstract TSelf Tan(TSelf x); + static abstract TSelf TanPi(TSelf x); } public partial interface IUnaryNegationOperators where TSelf : System.Numerics.IUnaryNegationOperators { diff --git a/src/libraries/System.Runtime/tests/System/DoubleTests.cs b/src/libraries/System.Runtime/tests/System/DoubleTests.cs index d849aac40f553..8e05c9c0df3dc 100644 --- a/src/libraries/System.Runtime/tests/System/DoubleTests.cs +++ b/src/libraries/System.Runtime/tests/System/DoubleTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; +using System.IO.Tests; using System.Linq; using Xunit; @@ -1405,5 +1406,164 @@ public static void Log10P1Test(double value, double expectedResult, double allow { AssertExtensions.Equal(expectedResult, double.Log10P1(value), allowedVariance); } + + [Theory] + [InlineData( double.NaN, double.NaN, 0.0)] + [InlineData( 1.0, 0.0, 0.0)] + [InlineData( 0.54030230586813972, 0.31830988618379067, CrossPlatformMachineEpsilon)] + [InlineData( 0.20495719432643395, 0.43429448190325183, CrossPlatformMachineEpsilon)] + [InlineData( 0.0, 0.5, 0.0)] + [InlineData(-0.41614683654714239, 0.63661977236758134, CrossPlatformMachineEpsilon)] + [InlineData(-0.57023324876887755, 0.69314718055994531, CrossPlatformMachineEpsilon)] + [InlineData(-0.60569986707881343, 0.70710678118654752, CrossPlatformMachineEpsilon)] + [InlineData(-0.78121189211048819, 0.78539816339744831, CrossPlatformMachineEpsilon)] + [InlineData(-1.0, 1.0, 0.0)] + [InlineData(-0.91976499476851874, 0.87162083290448743, CrossPlatformMachineEpsilon)] + [InlineData(-0.26625534204141549, 0.58578643762690495, CrossPlatformMachineEpsilon)] + [InlineData(-0.17905794598427576, 0.55730495911103659, CrossPlatformMachineEpsilon)] + [InlineData( 0.22058404074969809, 0.42920367320510338, CrossPlatformMachineEpsilon)] + [InlineData( 0.58119566361426737, 0.30258509299404568, CrossPlatformMachineEpsilon)] + [InlineData(-0.63325565131482003, 0.71828182845904523, CrossPlatformMachineEpsilon)] + [InlineData(-0.90268536193307107, 0.85840734641020676, CrossPlatformMachineEpsilon)] + public static void AcosPiTest(double value, double expectedResult, double allowedVariance) + { + AssertExtensions.Equal(expectedResult, double.AcosPi(value), allowedVariance); + } + + [Theory] + [InlineData( double.NaN, double.NaN, 0.0)] + [InlineData( 0.0, 0.0, 0.0)] + [InlineData( 0.84147098480789651, 0.31830988618379067, CrossPlatformMachineEpsilon)] + [InlineData( 0.97877093770393305, 0.43429448190325183, CrossPlatformMachineEpsilon)] + [InlineData( 1.0, 0.5, 0.0)] + [InlineData( 0.90929742682568170, 0.36338022763241866, CrossPlatformMachineEpsilon)] + [InlineData( 0.82148283122563883, 0.30685281944005469, CrossPlatformMachineEpsilon)] + [InlineData( 0.79569320156748087, 0.29289321881345248, CrossPlatformMachineEpsilon)] + [InlineData( 0.62426595263969903, 0.21460183660255169, CrossPlatformMachineEpsilon)] + [InlineData(-0.39246955856278420, -0.12837916709551257, CrossPlatformMachineEpsilon)] + [InlineData(-0.96390253284987733, -0.41421356237309505, CrossPlatformMachineEpsilon)] + [InlineData(-0.98383852942436249, -0.44269504088896341, CrossPlatformMachineEpsilon)] + [InlineData(-0.97536797208363139, -0.42920367320510338, CrossPlatformMachineEpsilon)] + [InlineData( 0.81376384817462330, 0.30258509299404568, CrossPlatformMachineEpsilon)] + [InlineData( 0.77394268526670828, 0.28171817154095476, CrossPlatformMachineEpsilon)] + [InlineData(-0.43030121700009227, -0.14159265358979324, CrossPlatformMachineEpsilon)] + public static void AsinPiTest(double value, double expectedResult, double allowedVariance) + { + AssertExtensions.Equal(-expectedResult, double.AsinPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, double.AsinPi(+value), allowedVariance); + } + + [Theory] + [InlineData( double.NaN, double.NaN, 0.0)] + [InlineData( 0.0, 0.0, 0.0)] + [InlineData( 1.5574077246549022, 0.31830988618379067, CrossPlatformMachineEpsilon)] + [InlineData( 4.7754895402454188, 0.43429448190325183, CrossPlatformMachineEpsilon)] + [InlineData( double.PositiveInfinity, 0.5, 0.0)] + [InlineData(-2.1850398632615190, -0.36338022763241866, CrossPlatformMachineEpsilon)] + [InlineData(-1.4406084404920341, -0.30685281944005469, CrossPlatformMachineEpsilon)] + [InlineData(-1.3136757077477542, -0.29289321881345248, CrossPlatformMachineEpsilon)] + [InlineData(-0.79909939792801821, -0.21460183660255169, CrossPlatformMachineEpsilon)] + [InlineData( 0.42670634433261806, 0.12837916709551257, CrossPlatformMachineEpsilon)] + [InlineData( 3.6202185671074506, 0.41421356237309505, CrossPlatformMachineEpsilon)] + [InlineData( 5.4945259425167300, 0.44269504088896341, CrossPlatformMachineEpsilon)] + [InlineData(-4.4217522209161288, -0.42920367320510338, CrossPlatformMachineEpsilon)] + [InlineData( 1.4001547140150527, 0.30258509299404568, CrossPlatformMachineEpsilon)] + [InlineData(-1.2221646718190066, -0.28171817154095476, CrossPlatformMachineEpsilon)] + [InlineData( 0.47669014603118892, 0.14159265358979324, CrossPlatformMachineEpsilon)] + public static void AtanPiTest(double value, double expectedResult, double allowedVariance) + { + AssertExtensions.Equal(-expectedResult, double.AtanPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, double.AtanPi(+value), allowedVariance); + } + + [Theory] + [InlineData(double.NaN, double.NaN, 0.0)] + [InlineData(0.0, 1.0, 0.0)] + [InlineData(0.31830988618379067, 0.54030230586813972, CrossPlatformMachineEpsilon)] // value: (1 / pi) + [InlineData(0.43429448190325183, 0.20495719432643395, CrossPlatformMachineEpsilon)] // value: (log10(e)) + [InlineData(0.5, 0.0, 0.0)] + [InlineData(0.63661977236758134, -0.41614683654714239, CrossPlatformMachineEpsilon)] // value: (2 / pi) + [InlineData(0.69314718055994531, -0.57023324876887755, CrossPlatformMachineEpsilon)] // value: (ln(2)) + [InlineData(0.70710678118654752, -0.60569986707881343, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) + [InlineData(0.78539816339744831, -0.78121189211048819, CrossPlatformMachineEpsilon)] // value: (pi / 4) + [InlineData(1.0, -1.0, 0.0)] + [InlineData(1.1283791670955126, -0.91976499476851874, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) + [InlineData(1.4142135623730950, -0.26625534204141549, CrossPlatformMachineEpsilon)] // value: (sqrt(2)) + [InlineData(1.4426950408889634, -0.17905794598427576, CrossPlatformMachineEpsilon)] // value: (log2(e)) + [InlineData(1.5, 0.0, 0.0)] + [InlineData(1.5707963267948966, 0.22058404074969809, CrossPlatformMachineEpsilon)] // value: (pi / 2) + [InlineData(2.0, 1.0, 0.0)] + [InlineData(2.3025850929940457, 0.58119566361426737, CrossPlatformMachineEpsilon)] // value: (ln(10)) + [InlineData(2.5, 0.0, 0.0)] + [InlineData(2.7182818284590452, -0.63325565131482003, CrossPlatformMachineEpsilon)] // value: (e) + [InlineData(3.0, -1.0, 0.0)] + [InlineData(3.1415926535897932, -0.90268536193307107, CrossPlatformMachineEpsilon)] // value: (pi) + [InlineData(3.5, 0.0, 0.0)] + [InlineData(double.PositiveInfinity, double.NaN, 0.0)] + public static void CosPiTest(double value, double expectedResult, double allowedVariance) + { + AssertExtensions.Equal(+expectedResult, double.CosPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, double.CosPi(+value), allowedVariance); + } + + [Theory] + [InlineData(double.NaN, double.NaN, 0.0)] + [InlineData(0.0, 0.0, 0.0)] + [InlineData(0.31830988618379067, 0.84147098480789651, CrossPlatformMachineEpsilon)] // value: (1 / pi) + [InlineData(0.43429448190325183, 0.97877093770393305, CrossPlatformMachineEpsilon)] // value: (log10(e)) + [InlineData(0.5, 1.0, 0.0)] + [InlineData(0.63661977236758134, 0.90929742682568170, CrossPlatformMachineEpsilon)] // value: (2 / pi) + [InlineData(0.69314718055994531, 0.82148283122563883, CrossPlatformMachineEpsilon)] // value: (ln(2)) + [InlineData(0.70710678118654752, 0.79569320156748087, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) + [InlineData(0.78539816339744831, 0.62426595263969903, CrossPlatformMachineEpsilon)] // value: (pi / 4) + [InlineData(1.0, 0.0, 0.0)] + [InlineData(1.1283791670955126, -0.39246955856278420, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) + [InlineData(1.4142135623730950, -0.96390253284987733, CrossPlatformMachineEpsilon)] // value: (sqrt(2)) + [InlineData(1.4426950408889634, -0.98383852942436249, CrossPlatformMachineEpsilon)] // value: (log2(e)) + [InlineData(1.5, -1.0, 0.0)] + [InlineData(1.5707963267948966, -0.97536797208363139, CrossPlatformMachineEpsilon)] // value: (pi / 2) + [InlineData(2.0, 0.0, 0.0)] + [InlineData(2.3025850929940457, 0.81376384817462330, CrossPlatformMachineEpsilon)] // value: (ln(10)) + [InlineData(2.5, 1.0, 0.0)] + [InlineData(2.7182818284590452, 0.77394268526670828, CrossPlatformMachineEpsilon)] // value: (e) + [InlineData(3.0, 0.0, 0.0)] + [InlineData(3.1415926535897932, -0.43030121700009227, CrossPlatformMachineEpsilon)] // value: (pi) + [InlineData(3.5, -1.0, 0.0)] + [InlineData(double.PositiveInfinity, double.NaN, 0.0)] + public static void SinPiTest(double value, double expectedResult, double allowedVariance) + { + AssertExtensions.Equal(-expectedResult, double.SinPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, double.SinPi(+value), allowedVariance); + } + + [Theory] + [InlineData(double.NaN, double.NaN, 0.0)] + [InlineData(0.0, 0.0, 0.0)] + [InlineData(0.31830988618379067, 1.5574077246549022, CrossPlatformMachineEpsilon * 10)] // value: (1 / pi) + [InlineData(0.43429448190325183, 4.7754895402454188, CrossPlatformMachineEpsilon * 10)] // value: (log10(e)) + [InlineData(0.5, double.PositiveInfinity, 0.0)] + [InlineData(0.63661977236758134, -2.1850398632615190, CrossPlatformMachineEpsilon * 10)] // value: (2 / pi) + [InlineData(0.69314718055994531, -1.4406084404920341, CrossPlatformMachineEpsilon * 10)] // value: (ln(2)) + [InlineData(0.70710678118654752, -1.3136757077477542, CrossPlatformMachineEpsilon * 10)] // value: (1 / sqrt(2)) + [InlineData(0.78539816339744831, -0.79909939792801821, CrossPlatformMachineEpsilon)] // value: (pi / 4) + [InlineData(1.0, -0.0, 0.0)] + [InlineData(1.1283791670955126, 0.42670634433261806, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) + [InlineData(1.4142135623730950, 3.6202185671074506, CrossPlatformMachineEpsilon * 10)] // value: (sqrt(2)) + [InlineData(1.4426950408889634, 5.4945259425167300, CrossPlatformMachineEpsilon * 10)] // value: (log2(e)) + [InlineData(1.5, double.NegativeInfinity, 0.0)] + [InlineData(1.5707963267948966, -4.4217522209161288, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2) + [InlineData(2.0, 0.0, 0.0)] + [InlineData(2.3025850929940457, 1.4001547140150527, CrossPlatformMachineEpsilon * 10)] // value: (ln(10)) + [InlineData(2.5, double.PositiveInfinity, 0.0)] + [InlineData(2.7182818284590452, -1.2221646718190066, CrossPlatformMachineEpsilon * 10)] // value: (e) + [InlineData(3.0, -0.0, 0.0)] + [InlineData(3.1415926535897932, 0.47669014603118892, CrossPlatformMachineEpsilon)] // value: (pi) + [InlineData(3.5, double.NegativeInfinity, 0.0)] + [InlineData(double.PositiveInfinity, double.NaN, 0.0)] + public static void TanPiTest(double value, double expectedResult, double allowedVariance) + { + AssertExtensions.Equal(-expectedResult, double.TanPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, double.TanPi(+value), allowedVariance); + } } } diff --git a/src/libraries/System.Runtime/tests/System/HalfTests.cs b/src/libraries/System.Runtime/tests/System/HalfTests.cs index 994536e410800..a8ea447c1f37d 100644 --- a/src/libraries/System.Runtime/tests/System/HalfTests.cs +++ b/src/libraries/System.Runtime/tests/System/HalfTests.cs @@ -1544,14 +1544,14 @@ public static IEnumerable Log10P1_TestData() yield return new object[] { (Half)(-2.71828183f), Half.NaN, (Half)0.0f }; // value: -(e) yield return new object[] { (Half)(-1.41421356f), Half.NaN, (Half)0.0f }; // value: -(sqrt(2)) yield return new object[] { Half.NaN, Half.NaN, (Half)0.0f }; - yield return new object[] { (Half)(-Half.One), Half.NegativeInfinity, (Half)0.0f }; + yield return new object[] { (Half)(-Half.One), Half.NegativeInfinity, (Half)0.0f }; yield return new object[] { (Half)(-0.998086986f), (Half)(-2.71828183f), CrossPlatformMachineEpsilon * (Half)10 }; // expected: -(e) yield return new object[] { (Half)(-0.995017872f), (Half)(-2.30258509f), CrossPlatformMachineEpsilon * (Half)10 }; // expected: -(ln(10)) yield return new object[] { (Half)(-0.973133959f), (Half)(-1.57079633f), CrossPlatformMachineEpsilon * (Half)10 }; // expected: -(pi / 2) yield return new object[] { (Half)(-0.963916807f), (Half)(-1.44269504f), CrossPlatformMachineEpsilon * (Half)10 }; // expected: -(log2(e)) yield return new object[] { (Half)(-0.961471115f), (Half)(-1.41421356f), CrossPlatformMachineEpsilon * (Half)10 }; // expected: -(sqrt(2)) yield return new object[] { (Half)(-0.925591794f), (Half)(-1.12837917f), CrossPlatformMachineEpsilon * (Half)10 }; // expected: -(2 / sqrt(pi)) - yield return new object[] { (Half)(-0.9f), (Half)(-Half.One), CrossPlatformMachineEpsilon * (Half)10 }; + yield return new object[] { (Half)(-0.9f), (Half)(-1.0f), CrossPlatformMachineEpsilon * (Half)10 }; yield return new object[] { (Half)(-0.836091364f), (Half)(-0.785398163f), CrossPlatformMachineEpsilon }; // expected: -(pi / 4) yield return new object[] { (Half)(-0.803712240f), (Half)(-0.707106781f), CrossPlatformMachineEpsilon }; // expected: -(1 / sqrt(2)) yield return new object[] { (Half)(-0.797300434f), (Half)(-0.693147181f), CrossPlatformMachineEpsilon }; // expected: -(ln(2)) @@ -1619,7 +1619,7 @@ public static IEnumerable Hypot_TestData() yield return new object[] { (Half)10.0f, (Half)0.693147181f, (Half)10.0239939f, CrossPlatformMachineEpsilon * (Half)100 }; // y: (ln(2)) yield return new object[] { (Half)10.0f, (Half)0.707106781f, (Half)10.0249688f, CrossPlatformMachineEpsilon * (Half)100 }; // y: (1 / sqrt(2)) yield return new object[] { (Half)10.0f, (Half)0.785398163f, (Half)10.0307951f, CrossPlatformMachineEpsilon * (Half)100 }; // y: (pi / 4) - yield return new object[] { (Half)10.0f, Half.One, (Half)10.0498756f, CrossPlatformMachineEpsilon * (Half)100 }; // + yield return new object[] { (Half)10.0f, Half.One, (Half)10.0498756f, CrossPlatformMachineEpsilon * (Half)100 }; // yield return new object[] { (Half)10.0f, (Half)1.12837917f, (Half)10.0634606f, CrossPlatformMachineEpsilon * (Half)100 }; // y: (2 / sqrt(pi)) yield return new object[] { (Half)10.0f, (Half)1.41421356f, (Half)10.0995049f, CrossPlatformMachineEpsilon * (Half)100 }; // y: (sqrt(2)) yield return new object[] { (Half)10.0f, (Half)1.44269504f, (Half)10.1035325f, CrossPlatformMachineEpsilon * (Half)100 }; // y: (log2(e)) @@ -1695,7 +1695,7 @@ public static IEnumerable Root_TestData() yield return new object[] {-Half.Zero, 2, Half.Zero, Half.Zero }; yield return new object[] {-Half.Zero, 3, -Half.Zero, Half.Zero }; yield return new object[] {-Half.Zero, 4, Half.Zero, Half.Zero }; - yield return new object[] {-Half.Zero, 5, -Half.Zero, Half.Zero }; + yield return new object[] {-Half.Zero, 5, -Half.Zero, Half.Zero }; yield return new object[] { Half.NaN, -5, Half.NaN, Half.Zero }; yield return new object[] { Half.NaN, -4, Half.NaN, Half.Zero }; yield return new object[] { Half.NaN, -3, Half.NaN, Half.Zero }; @@ -1759,5 +1759,194 @@ public static void Root(Half x, int n, Half expectedResult, Half allowedVariance { AssertExtensions.Equal(expectedResult, Half.Root(x, n), allowedVariance); } + + public static IEnumerable AcosPi_TestData() + { + yield return new object[] { Half.NaN, Half.NaN, Half.Zero }; + yield return new object[] { Half.One, Half.Zero, Half.Zero }; + yield return new object[] { (Half)0.540302306f, (Half)0.318309886f, CrossPlatformMachineEpsilon }; + yield return new object[] { (Half)0.204957194f, (Half)0.434294482f, CrossPlatformMachineEpsilon }; + yield return new object[] { Half.Zero, (Half)0.5f, Half.Zero }; + yield return new object[] { -(Half)0.416146837f, (Half)0.636619772f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(Half)0.570233249f, (Half)0.693147181f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(Half)0.605699867f, (Half)0.707106781f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(Half)0.781211892f, (Half)0.785398163f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(Half)1.0f, Half.One, Half.Zero }; + yield return new object[] { -(Half)0.919764995f, (Half)0.871620833f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(Half)0.266255342f, (Half)0.585786438f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(Half)0.179057946f, (Half)0.557304959f, CrossPlatformMachineEpsilon }; + yield return new object[] { (Half)0.220584041f, (Half)0.429203673f, CrossPlatformMachineEpsilon }; + yield return new object[] { (Half)0.581195664f, (Half)0.302585093f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(Half)0.633255651f, (Half)0.718281828f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(Half)0.902685362f, (Half)0.858407346f, CrossPlatformMachineEpsilon }; + } + + [Theory] + [MemberData(nameof(AcosPi_TestData))] + public static void AcosPiTest(Half value, Half expectedResult, Half allowedVariance) + { + AssertExtensions.Equal(expectedResult, Half.AcosPi(value), allowedVariance); + } + + public static IEnumerable AsinPi_TestData() + { + yield return new object[] { Half.NaN, Half.NaN, Half.Zero }; + yield return new object[] { Half.Zero, Half.Zero, Half.Zero }; + yield return new object[] { (Half)0.841470985f, (Half)0.318309886f, CrossPlatformMachineEpsilon }; + yield return new object[] { (Half)0.978770938f, (Half)0.434294482f, CrossPlatformMachineEpsilon }; + yield return new object[] { Half.One, (Half)0.5f, Half.Zero }; + yield return new object[] { (Half)0.909297427f, (Half)0.363380228f, CrossPlatformMachineEpsilon }; + yield return new object[] { (Half)0.821482831f, (Half)0.306852819f, CrossPlatformMachineEpsilon }; + yield return new object[] { (Half)0.795693202f, (Half)0.292893219f, CrossPlatformMachineEpsilon }; + yield return new object[] { (Half)0.624265953f, (Half)0.214601837f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(Half)0.392469559f, -(Half)0.128379167f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(Half)0.963902533f, -(Half)0.414213562f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(Half)0.983838529f, -(Half)0.442695041f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(Half)0.975367972f, -(Half)0.429203673f, CrossPlatformMachineEpsilon }; + yield return new object[] { (Half)0.813763848f, (Half)0.302585093f, CrossPlatformMachineEpsilon }; + yield return new object[] { (Half)0.773942685f, (Half)0.281718172f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(Half)0.430301217f, -(Half)0.141592654f, CrossPlatformMachineEpsilon }; + } + + [Theory] + [MemberData(nameof(AsinPi_TestData))] + public static void AsinPiTest(Half value, Half expectedResult, Half allowedVariance) + { + AssertExtensions.Equal(-expectedResult, Half.AsinPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, Half.AsinPi(+value), allowedVariance); + } + + public static IEnumerable AtanPi_TestData() + { + yield return new object[] { Half.NaN, Half.NaN, Half.Zero }; + yield return new object[] { Half.Zero, Half.Zero, Half.Zero }; + yield return new object[] { (Half)1.55740773f, (Half)0.318309886f, CrossPlatformMachineEpsilon }; + yield return new object[] { (Half)4.77548954f, (Half)0.434294482f, CrossPlatformMachineEpsilon }; + yield return new object[] { Half.PositiveInfinity, (Half)0.5f, Half.Zero }; + yield return new object[] { -(Half)2.18503986f, -(Half)0.363380228f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(Half)1.44060844f, -(Half)0.306852819f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(Half)1.31367571f, -(Half)0.292893219f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(Half)0.79909940f, -(Half)0.214601837f, CrossPlatformMachineEpsilon }; + yield return new object[] { (Half)0.42670634f, (Half)0.128379167f, CrossPlatformMachineEpsilon }; + yield return new object[] { (Half)3.62021857f, (Half)0.414213562f, CrossPlatformMachineEpsilon }; + yield return new object[] { (Half)5.49452594f, (Half)0.442695041f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(Half)4.42175222f, -(Half)0.429203673f, CrossPlatformMachineEpsilon }; + yield return new object[] { (Half)1.40015471f, (Half)0.302585093f, CrossPlatformMachineEpsilon }; + yield return new object[] { -(Half)1.22216467f, -(Half)0.281718172f, CrossPlatformMachineEpsilon }; + yield return new object[] { (Half)0.476690146f, (Half)0.141592654f, CrossPlatformMachineEpsilon }; + } + + [Theory] + [MemberData(nameof(AtanPi_TestData))] + public static void AtanPiTest(Half value, Half expectedResult, Half allowedVariance) + { + AssertExtensions.Equal(-expectedResult, Half.AtanPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, Half.AtanPi(+value), allowedVariance); + } + + public static IEnumerable CosPi_TestData() + { + yield return new object[] { Half.NaN, Half.NaN, Half.Zero }; + yield return new object[] { Half.Zero, Half.One, Half.Zero }; + yield return new object[] { (Half)0.318309886f, (Half)0.540302306f, CrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { (Half)0.434294482f, (Half)0.204957194f, CrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { (Half)0.5f, Half.Zero, Half.Zero }; + yield return new object[] { (Half)0.636619772f, -(Half)0.416146837f, CrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { (Half)0.693147181f, -(Half)0.570233249f, CrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { (Half)0.707106781f, -(Half)0.605699867f, CrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { (Half)0.785398163f, -(Half)0.781211892f, CrossPlatformMachineEpsilon }; // value: (pi / 4) + yield return new object[] { Half.One, -(Half)1.0f, Half.Zero }; + yield return new object[] { (Half)1.12837917f, -(Half)0.919764995f, CrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { (Half)1.41421356f, -(Half)0.266255342f, CrossPlatformMachineEpsilon }; // value: (sqrt(2)) + yield return new object[] { (Half)1.44269504f, -(Half)0.179057946f, CrossPlatformMachineEpsilon }; // value: (log2(e)) + yield return new object[] { (Half)1.5f, Half.Zero, Half.Zero }; + yield return new object[] { (Half)1.57079633f, (Half)0.220584041f, CrossPlatformMachineEpsilon }; // value: (pi / 2) + yield return new object[] { (Half)2.0f, (Half)1.0, Half.Zero }; + yield return new object[] { (Half)2.30258509f, (Half)0.581195664f, CrossPlatformMachineEpsilon }; // value: (ln(10)) + yield return new object[] { (Half)2.5f, Half.Zero, Half.Zero }; + yield return new object[] { (Half)2.71828183f, -(Half)0.633255651f, CrossPlatformMachineEpsilon }; // value: (e) + yield return new object[] { (Half)3.0f, -(Half)1.0, Half.Zero }; + yield return new object[] { (Half)3.14159265f, -(Half)0.902685362f, CrossPlatformMachineEpsilon }; // value: (pi) + yield return new object[] { (Half)3.5f, Half.Zero, Half.Zero }; + yield return new object[] { Half.PositiveInfinity, Half.NaN, Half.Zero }; + } + + [Theory] + [MemberData(nameof(CosPi_TestData))] + public static void CosPiTest(Half value, Half expectedResult, Half allowedVariance) + { + AssertExtensions.Equal(+expectedResult, Half.CosPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, Half.CosPi(+value), allowedVariance); + } + + public static IEnumerable SinPi_TestData() + { + yield return new object[] { Half.NaN, Half.NaN, Half.Zero }; + yield return new object[] { Half.Zero, Half.Zero, Half.Zero }; + yield return new object[] { (Half)0.318309886f, (Half)0.841470985f, CrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { (Half)0.434294482f, (Half)0.978770938f, CrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { (Half)0.5f, Half.One, Half.Zero }; + yield return new object[] { (Half)0.636619772f, (Half)0.909297427f, CrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { (Half)0.693147181f, (Half)0.821482831f, CrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { (Half)0.707106781f, (Half)0.795693202f, CrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { (Half)0.785398163f, (Half)0.624265953f, CrossPlatformMachineEpsilon }; // value: (pi / 4) + yield return new object[] { Half.One, Half.Zero, Half.Zero }; + yield return new object[] { (Half)1.12837917f, -(Half)0.392469559f, CrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { (Half)1.41421356f, -(Half)0.963902533f, CrossPlatformMachineEpsilon }; // value: (sqrt(2)) + yield return new object[] { (Half)1.44269504f, -(Half)0.983838529f, CrossPlatformMachineEpsilon }; // value: (log2(e)) + yield return new object[] { (Half)1.5f, -(Half)1.0f, Half.Zero }; + yield return new object[] { (Half)1.57079633f, -(Half)0.975367972f, CrossPlatformMachineEpsilon }; // value: (pi / 2) + yield return new object[] { (Half)2.0f, Half.Zero, Half.Zero }; + yield return new object[] { (Half)2.30258509f, (Half)0.813763848f, CrossPlatformMachineEpsilon }; // value: (ln(10)) + yield return new object[] { (Half)2.5f, Half.One, Half.Zero }; + yield return new object[] { (Half)2.71828183f, (Half)0.773942685f, CrossPlatformMachineEpsilon }; // value: (e) + yield return new object[] { (Half)3.0f, Half.Zero, Half.Zero }; + yield return new object[] { (Half)3.14159265f, -(Half)0.430301217f, CrossPlatformMachineEpsilon }; // value: (pi) + yield return new object[] { (Half)3.5f, -(Half)1.0f, Half.Zero }; + yield return new object[] { Half.PositiveInfinity, Half.NaN, Half.Zero }; + } + + [Theory] + [MemberData(nameof(SinPi_TestData))] + public static void SinPiTest(Half value, Half expectedResult, Half allowedVariance) + { + AssertExtensions.Equal(-expectedResult, Half.SinPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, Half.SinPi(+value), allowedVariance); + } + + public static IEnumerable TanPi_TestData() + { + yield return new object[] { Half.NaN, Half.NaN, Half.Zero }; + yield return new object[] { Half.Zero, Half.Zero, Half.Zero }; + yield return new object[] { (Half)0.318309886f, (Half)1.55740772f, CrossPlatformMachineEpsilon * (Half)10 }; // value: (1 / pi) + yield return new object[] { (Half)0.434294482f, (Half)4.77548954f, CrossPlatformMachineEpsilon * (Half)10 }; // value: (log10(e)) + yield return new object[] { (Half)0.5f, Half.PositiveInfinity, Half.Zero }; + yield return new object[] { (Half)0.636619772f, -(Half)2.18503986f, CrossPlatformMachineEpsilon * (Half)10 }; // value: (2 / pi) + yield return new object[] { (Half)0.693147181f, -(Half)1.44060844f, CrossPlatformMachineEpsilon * (Half)10 }; // value: (ln(2)) + yield return new object[] { (Half)0.707106781f, -(Half)1.31367571f, CrossPlatformMachineEpsilon * (Half)10 }; // value: (1 / sqrt(2)) + yield return new object[] { (Half)0.785398163f, -(Half)0.799099398f, CrossPlatformMachineEpsilon }; // value: (pi / 4) + yield return new object[] { Half.One, -Half.Zero, Half.Zero }; + yield return new object[] { (Half)1.12837917f, (Half)0.426706344f, CrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { (Half)1.41421356f, (Half)3.62021857f, CrossPlatformMachineEpsilon * (Half)10 }; // value: (sqrt(2)) + yield return new object[] { (Half)1.44269504f, (Half)5.49452594f, CrossPlatformMachineEpsilon * (Half)10 }; // value: (log2(e)) + yield return new object[] { (Half)1.5f, Half.NegativeInfinity, Half.Zero }; + yield return new object[] { (Half)1.57079633f, -(Half)4.42175222f, CrossPlatformMachineEpsilon * (Half)10 }; // value: (pi / 2) + yield return new object[] { (Half)2.0f, Half.Zero, Half.Zero }; + yield return new object[] { (Half)2.30258509f, (Half)1.40015471f, CrossPlatformMachineEpsilon * (Half)10 }; // value: (ln(10)) + yield return new object[] { (Half)2.5f, Half.PositiveInfinity, Half.Zero }; + yield return new object[] { (Half)2.71828183f, -(Half)1.22216467f, CrossPlatformMachineEpsilon * (Half)10 }; // value: (e) + yield return new object[] { (Half)3.0f, -Half.Zero, Half.Zero }; + yield return new object[] { (Half)3.14159265f, (Half)0.476690146f, CrossPlatformMachineEpsilon }; // value: (pi) + yield return new object[] { (Half)3.5f, Half.NegativeInfinity, Half.Zero }; + yield return new object[] { Half.PositiveInfinity, Half.NaN, Half.Zero }; + } + + [Theory] + [MemberData(nameof(TanPi_TestData))] + public static void TanPiTest(Half value, Half expectedResult, Half allowedVariance) + { + AssertExtensions.Equal(-expectedResult, Half.TanPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, Half.TanPi(+value), allowedVariance); + } } } diff --git a/src/libraries/System.Runtime/tests/System/SingleTests.cs b/src/libraries/System.Runtime/tests/System/SingleTests.cs index 62b00c3152b1b..a48cf9db86b1e 100644 --- a/src/libraries/System.Runtime/tests/System/SingleTests.cs +++ b/src/libraries/System.Runtime/tests/System/SingleTests.cs @@ -1336,5 +1336,164 @@ public static void Log10P1Test(float value, float expectedResult, float allowedV { AssertExtensions.Equal(expectedResult, float.Log10P1(value), allowedVariance); } + + [Theory] + [InlineData( float.NaN, float.NaN, 0.0f)] + [InlineData( 1.0f, 0.0f, 0.0f)] + [InlineData( 0.540302306f, 0.318309886f, CrossPlatformMachineEpsilon)] + [InlineData( 0.204957194f, 0.434294482f, CrossPlatformMachineEpsilon)] + [InlineData( 0.0f, 0.5f, CrossPlatformMachineEpsilon)] // This should be exact, but has an issue on WASM/Unix + [InlineData(-0.416146837f, 0.636619772f, CrossPlatformMachineEpsilon)] + [InlineData(-0.570233249f, 0.693147181f, CrossPlatformMachineEpsilon)] + [InlineData(-0.605699867f, 0.707106781f, CrossPlatformMachineEpsilon)] + [InlineData(-0.781211892f, 0.785398163f, CrossPlatformMachineEpsilon)] + [InlineData(-1.0f, 1.0f, CrossPlatformMachineEpsilon)] // This should be exact, but has an issue on WASM/Unix + [InlineData(-0.919764995f, 0.871620833f, CrossPlatformMachineEpsilon)] + [InlineData(-0.266255342f, 0.585786438f, CrossPlatformMachineEpsilon)] + [InlineData(-0.179057946f, 0.557304959f, CrossPlatformMachineEpsilon)] + [InlineData( 0.220584041f, 0.429203673f, CrossPlatformMachineEpsilon)] + [InlineData( 0.581195664f, 0.302585093f, CrossPlatformMachineEpsilon)] + [InlineData(-0.633255651f, 0.718281828f, CrossPlatformMachineEpsilon)] + [InlineData(-0.902685362f, 0.858407346f, CrossPlatformMachineEpsilon)] + public static void AcosPiTest(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, float.AcosPi(value), allowedVariance); + } + + [Theory] + [InlineData( float.NaN, float.NaN, 0.0f)] + [InlineData( 0.0f, 0.0f, 0.0f)] + [InlineData( 0.841470985f, 0.318309886f, CrossPlatformMachineEpsilon)] + [InlineData( 0.978770938f, 0.434294482f, CrossPlatformMachineEpsilon)] + [InlineData( 1.0f, 0.5f, CrossPlatformMachineEpsilon)] // This should be exact, but has an issue on WASM/Unix + [InlineData( 0.909297427f, 0.363380228f, CrossPlatformMachineEpsilon)] + [InlineData( 0.821482831f, 0.306852819f, CrossPlatformMachineEpsilon)] + [InlineData( 0.795693202f, 0.292893219f, CrossPlatformMachineEpsilon)] + [InlineData( 0.624265953f, 0.214601837f, CrossPlatformMachineEpsilon)] + [InlineData(-0.392469559f, -0.128379167f, CrossPlatformMachineEpsilon)] + [InlineData(-0.963902533f, -0.414213562f, CrossPlatformMachineEpsilon)] + [InlineData(-0.983838529f, -0.442695041f, CrossPlatformMachineEpsilon)] + [InlineData(-0.975367972f, -0.429203673f, CrossPlatformMachineEpsilon)] + [InlineData( 0.813763848f, 0.302585093f, CrossPlatformMachineEpsilon)] + [InlineData( 0.773942685f, 0.281718172f, CrossPlatformMachineEpsilon)] + [InlineData(-0.430301217f, -0.141592654f, CrossPlatformMachineEpsilon)] + public static void AsinPiTest(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(-expectedResult, float.AsinPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, float.AsinPi(+value), allowedVariance); + } + + [Theory] + [InlineData( float.NaN, float.NaN, 0.0f)] + [InlineData( 0.0f, 0.0f, 0.0f)] + [InlineData( 1.55740773f, 0.318309886f, CrossPlatformMachineEpsilon)] + [InlineData( 4.77548954f, 0.434294482f, CrossPlatformMachineEpsilon)] + [InlineData( float.PositiveInfinity, 0.5f, CrossPlatformMachineEpsilon)] // This should be exact, but has an issue on WASM/Unix + [InlineData(-2.18503986f, -0.363380228f, CrossPlatformMachineEpsilon)] + [InlineData(-1.44060844f, -0.306852819f, CrossPlatformMachineEpsilon)] + [InlineData(-1.31367571f, -0.292893219f, CrossPlatformMachineEpsilon)] + [InlineData(-0.79909940f, -0.214601837f, CrossPlatformMachineEpsilon)] + [InlineData( 0.42670634f, 0.128379167f, CrossPlatformMachineEpsilon)] + [InlineData( 3.62021857f, 0.414213562f, CrossPlatformMachineEpsilon)] + [InlineData( 5.49452594f, 0.442695041f, CrossPlatformMachineEpsilon)] + [InlineData(-4.42175222f, -0.429203673f, CrossPlatformMachineEpsilon)] + [InlineData( 1.40015471f, 0.302585093f, CrossPlatformMachineEpsilon)] + [InlineData(-1.22216467f, -0.281718172f, CrossPlatformMachineEpsilon)] + [InlineData( 0.476690146f, 0.141592654f, CrossPlatformMachineEpsilon)] + public static void AtanPiTest(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(-expectedResult, float.AtanPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, float.AtanPi(+value), allowedVariance); + } + + [Theory] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 1.0f, 0.0f)] + [InlineData(0.318309886f, 0.540302306f, CrossPlatformMachineEpsilon)] // value: (1 / pi) + [InlineData(0.434294482f, 0.204957194f, CrossPlatformMachineEpsilon)] // value: (log10(e)) + [InlineData(0.5f, 0.0f, 0.0f)] + [InlineData(0.636619772f, -0.416146837f, CrossPlatformMachineEpsilon)] // value: (2 / pi) + [InlineData(0.693147181f, -0.570233249f, CrossPlatformMachineEpsilon)] // value: (ln(2)) + [InlineData(0.707106781f, -0.605699867f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, -0.781211892f, CrossPlatformMachineEpsilon)] // value: (pi / 4) + [InlineData(1.0f, -1.0f, 0.0f)] + [InlineData(1.12837917f, -0.919764995f, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, -0.266255342f, CrossPlatformMachineEpsilon)] // value: (sqrt(2)) + [InlineData(1.44269504f, -0.179057946f, CrossPlatformMachineEpsilon)] // value: (log2(e)) + [InlineData(1.5f, 0.0f, 0.0f)] + [InlineData(1.57079633f, 0.220584041f, CrossPlatformMachineEpsilon)] // value: (pi / 2) + [InlineData(2.0f, 1.0f, 0.0f)] + [InlineData(2.30258509f, 0.581195664f, CrossPlatformMachineEpsilon)] // value: (ln(10)) + [InlineData(2.5f, 0.0f, 0.0f)] + [InlineData(2.71828183f, -0.633255651f, CrossPlatformMachineEpsilon)] // value: (e) + [InlineData(3.0f, -1.0f, 0.0f)] + [InlineData(3.14159265f, -0.902685362f, CrossPlatformMachineEpsilon)] // value: (pi) + [InlineData(3.5f, 0.0f, 0.0f)] + [InlineData(float.PositiveInfinity, float.NaN, 0.0f)] + public static void CosPiTest(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(+expectedResult, float.CosPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, float.CosPi(+value), allowedVariance); + } + + [Theory] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 0.841470985f, CrossPlatformMachineEpsilon)] // value: (1 / pi) + [InlineData(0.434294482f, 0.978770938f, CrossPlatformMachineEpsilon)] // value: (log10(e)) + [InlineData(0.5f, 1.0f, 0.0f)] + [InlineData(0.636619772f, 0.909297427f, CrossPlatformMachineEpsilon)] // value: (2 / pi) + [InlineData(0.693147181f, 0.821482831f, CrossPlatformMachineEpsilon)] // value: (ln(2)) + [InlineData(0.707106781f, 0.795693202f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 0.624265953f, CrossPlatformMachineEpsilon)] // value: (pi / 4) + [InlineData(1.0f, 0.0f, 0.0f)] + [InlineData(1.12837917f, -0.392469559f, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, -0.963902533f, CrossPlatformMachineEpsilon)] // value: (sqrt(2)) + [InlineData(1.44269504f, -0.983838529f, CrossPlatformMachineEpsilon)] // value: (log2(e)) + [InlineData(1.5f, -1.0f, 0.0f)] + [InlineData(1.57079633f, -0.975367972f, CrossPlatformMachineEpsilon)] // value: (pi / 2) + [InlineData(2.0f, 0.0f, 0.0f)] + [InlineData(2.30258509f, 0.813763848f, CrossPlatformMachineEpsilon)] // value: (ln(10)) + [InlineData(2.5f, 1.0f, 0.0f)] + [InlineData(2.71828183f, 0.773942685f, CrossPlatformMachineEpsilon)] // value: (e) + [InlineData(3.0f, 0.0f, 0.0f)] + [InlineData(3.14159265f, -0.430301217f, CrossPlatformMachineEpsilon)] // value: (pi) + [InlineData(3.5f, -1.0f, 0.0f)] + [InlineData(float.PositiveInfinity, float.NaN, 0.0f)] + public static void SinPiTest(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(-expectedResult, float.SinPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, float.SinPi(+value), allowedVariance); + } + + [Theory] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 1.55740772f, CrossPlatformMachineEpsilon * 10)] // value: (1 / pi) + [InlineData(0.434294482f, 4.77548954f, CrossPlatformMachineEpsilon * 10)] // value: (log10(e)) + [InlineData(0.5f, float.PositiveInfinity, 0.0f)] + [InlineData(0.636619772f, -2.18503986f, CrossPlatformMachineEpsilon * 10)] // value: (2 / pi) + [InlineData(0.693147181f, -1.44060844f, CrossPlatformMachineEpsilon * 10)] // value: (ln(2)) + [InlineData(0.707106781f, -1.31367571f, CrossPlatformMachineEpsilon * 10)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, -0.799099398f, CrossPlatformMachineEpsilon)] // value: (pi / 4) + [InlineData(1.0f, -0.0f, 0.0f)] + [InlineData(1.12837917f, 0.426706344f, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 3.62021857f, CrossPlatformMachineEpsilon * 10)] // value: (sqrt(2)) + [InlineData(1.44269504f, 5.49452594f, CrossPlatformMachineEpsilon * 10)] // value: (log2(e)) + [InlineData(1.5f, float.NegativeInfinity, 0.0f)] + [InlineData(1.57079633f, -4.42175222f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2) + [InlineData(2.0f, 0.0f, 0.0f)] + [InlineData(2.30258509f, 1.40015471f, CrossPlatformMachineEpsilon * 10)] // value: (ln(10)) + [InlineData(2.5f, float.PositiveInfinity, 0.0f)] + [InlineData(2.71828183f, -1.22216467f, CrossPlatformMachineEpsilon * 10)] // value: (e) + [InlineData(3.0f, -0.0f, 0.0f)] + [InlineData(3.14159265f, 0.476690146f, CrossPlatformMachineEpsilon)] // value: (pi) + [InlineData(3.5f, float.NegativeInfinity, 0.0f)] + [InlineData(float.PositiveInfinity, float.NaN, 0.0f)] + public static void TanPiTest(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(-expectedResult, float.TanPi(-value), allowedVariance); + AssertExtensions.Equal(+expectedResult, float.TanPi(+value), allowedVariance); + } } }