diff --git a/src/libraries/Common/tests/System/GenericMathTestMemberData.cs b/src/libraries/Common/tests/System/GenericMathTestMemberData.cs index 2e40a0940fc5a0..0e19ac826dfdda 100644 --- a/src/libraries/Common/tests/System/GenericMathTestMemberData.cs +++ b/src/libraries/Common/tests/System/GenericMathTestMemberData.cs @@ -198,6 +198,86 @@ public static IEnumerable CopySignSingle } } + public static IEnumerable CosDouble + { + get + { + yield return new object[] { double.NegativeInfinity, double.NaN, 0.0 }; + yield return new object[] { -3.1415926535897932, -1.0, DoubleCrossPlatformMachineEpsilon * 10 }; // value: -(pi) + yield return new object[] { -2.7182818284590452, -0.91173391478696510, DoubleCrossPlatformMachineEpsilon }; // value: -(e) + yield return new object[] { -2.3025850929940457, -0.66820151019031295, DoubleCrossPlatformMachineEpsilon }; // value: -(ln(10)) + yield return new object[] { -1.5707963267948966, 0.0, DoubleCrossPlatformMachineEpsilon }; // value: -(pi / 2) + yield return new object[] { -1.4426950408889634, 0.12775121753523991, DoubleCrossPlatformMachineEpsilon }; // value: -(log2(e)) + yield return new object[] { -1.4142135623730950, 0.15594369476537447, DoubleCrossPlatformMachineEpsilon }; // value: -(sqrt(2)) + yield return new object[] { -1.1283791670955126, 0.42812514788535792, DoubleCrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) + yield return new object[] { -1.0, 0.54030230586813972, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { -0.78539816339744831, 0.70710678118654752, DoubleCrossPlatformMachineEpsilon }; // value: -(pi / 4), expected: (1 / sqrt(2)) + yield return new object[] { -0.70710678118654752, 0.76024459707563015, DoubleCrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) + yield return new object[] { -0.69314718055994531, 0.76923890136397213, DoubleCrossPlatformMachineEpsilon }; // value: -(ln(2)) + yield return new object[] { -0.63661977236758134, 0.80410982822879171, DoubleCrossPlatformMachineEpsilon }; // value: -(2 / pi) + yield return new object[] { -0.43429448190325183, 0.90716712923909839, DoubleCrossPlatformMachineEpsilon }; // value: -(log10(e)) + yield return new object[] { -0.31830988618379067, 0.94976571538163866, DoubleCrossPlatformMachineEpsilon }; // value: -(1 / pi) + yield return new object[] { -0.0, 1.0, DoubleCrossPlatformMachineEpsilon * 10 }; + yield return new object[] { double.NaN, double.NaN, 0.0 }; + yield return new object[] { 0.0, 1.0, DoubleCrossPlatformMachineEpsilon * 10 }; + yield return new object[] { 0.31830988618379067, 0.94976571538163866, DoubleCrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { 0.43429448190325183, 0.90716712923909839, DoubleCrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { 0.63661977236758134, 0.80410982822879171, DoubleCrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { 0.69314718055994531, 0.76923890136397213, DoubleCrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { 0.70710678118654752, 0.76024459707563015, DoubleCrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { 0.78539816339744831, 0.70710678118654752, DoubleCrossPlatformMachineEpsilon }; // value: (pi / 4), expected: (1 / sqrt(2)) + yield return new object[] { 1.0, 0.54030230586813972, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { 1.1283791670955126, 0.42812514788535792, DoubleCrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { 1.4142135623730950, 0.15594369476537447, DoubleCrossPlatformMachineEpsilon }; // value: (sqrt(2)) + yield return new object[] { 1.4426950408889634, 0.12775121753523991, DoubleCrossPlatformMachineEpsilon }; // value: (log2(e)) + yield return new object[] { 1.5707963267948966, 0.0, DoubleCrossPlatformMachineEpsilon }; // value: (pi / 2) + yield return new object[] { 2.3025850929940457, -0.66820151019031295, DoubleCrossPlatformMachineEpsilon }; // value: (ln(10)) + yield return new object[] { 2.7182818284590452, -0.91173391478696510, DoubleCrossPlatformMachineEpsilon }; // value: (e) + yield return new object[] { 3.1415926535897932, -1.0, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (pi) + yield return new object[] { double.PositiveInfinity, double.NaN, 0.0 }; + } + } + + public static IEnumerable CosSingle + { + get + { + yield return new object[] { float.NegativeInfinity, float.NaN, 0.0f }; + yield return new object[] { -3.14159265f, -1.0f, SingleCrossPlatformMachineEpsilon * 10 }; // value: -(pi) + yield return new object[] { -2.71828183f, -0.911733918f, SingleCrossPlatformMachineEpsilon }; // value: -(e) + yield return new object[] { -2.30258509f, -0.668201510f, SingleCrossPlatformMachineEpsilon }; // value: -(ln(10)) + yield return new object[] { -1.57079633f, 0.0f, SingleCrossPlatformMachineEpsilon }; // value: -(pi / 2) + yield return new object[] { -1.44269504f, 0.127751218f, SingleCrossPlatformMachineEpsilon }; // value: -(log2(e)) + yield return new object[] { -1.41421356f, 0.155943695f, SingleCrossPlatformMachineEpsilon }; // value: -(sqrt(2)) + yield return new object[] { -1.12837917f, 0.428125148f, SingleCrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) + yield return new object[] { -1.0f, 0.540302306f, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { -0.785398163f, 0.707106781f, SingleCrossPlatformMachineEpsilon }; // value: -(pi / 4), expected: (1 / sqrt(2)) + yield return new object[] { -0.707106781f, 0.760244597f, SingleCrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) + yield return new object[] { -0.693147181f, 0.769238901f, SingleCrossPlatformMachineEpsilon }; // value: -(ln(2)) + yield return new object[] { -0.636619772f, 0.804109828f, SingleCrossPlatformMachineEpsilon }; // value: -(2 / pi) + yield return new object[] { -0.434294482f, 0.907167129f, SingleCrossPlatformMachineEpsilon }; // value: -(log10(e)) + yield return new object[] { -0.318309886f, 0.949765715f, SingleCrossPlatformMachineEpsilon }; // value: -(1 / pi) + yield return new object[] { -0.0f, 1.0f, SingleCrossPlatformMachineEpsilon * 10 }; + yield return new object[] { float.NaN, float.NaN, 0.0f }; + yield return new object[] { 0.0f, 1.0f, SingleCrossPlatformMachineEpsilon * 10 }; + yield return new object[] { 0.318309886f, 0.949765715f, SingleCrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { 0.434294482f, 0.907167129f, SingleCrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { 0.636619772f, 0.804109828f, SingleCrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { 0.693147181f, 0.769238901f, SingleCrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { 0.707106781f, 0.760244597f, SingleCrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { 0.785398163f, 0.707106781f, SingleCrossPlatformMachineEpsilon }; // value: (pi / 4), expected: (1 / sqrt(2)) + yield return new object[] { 1.0f, 0.540302306f, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { 1.12837917f, 0.428125148f, SingleCrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { 1.41421356f, 0.155943695f, SingleCrossPlatformMachineEpsilon }; // value: (sqrt(2)) + yield return new object[] { 1.44269504f, 0.127751218f, SingleCrossPlatformMachineEpsilon }; // value: (log2(e)) + yield return new object[] { 1.57079633f, 0.0f, SingleCrossPlatformMachineEpsilon }; // value: (pi / 2) + yield return new object[] { 2.30258509f, -0.668201510f, SingleCrossPlatformMachineEpsilon }; // value: (ln(10)) + yield return new object[] { 2.71828183f, -0.911733918f, SingleCrossPlatformMachineEpsilon }; // value: (e) + yield return new object[] { 3.14159265f, -1.0f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (pi) + yield return new object[] { float.PositiveInfinity, float.NaN, 0.0f }; + } + } + public static IEnumerable DegreesToRadiansDouble { get @@ -981,7 +1061,7 @@ public static IEnumerable Log2Double yield return new object[] { 0.64321824193300488, -0.63661977236758126, DoubleCrossPlatformMachineEpsilon }; // expected: -(2 / pi) yield return new object[] { 0.74005557395545179, -0.43429448190325190, DoubleCrossPlatformMachineEpsilon }; // expected: -(log10(e)) yield return new object[] { 0.80200887896145195, -0.31830988618379073, DoubleCrossPlatformMachineEpsilon }; // expected: -(1 / pi) - yield return new object[] { 1, 0.0, 0.0 }; + yield return new object[] { 1, 0.0, 0.0 }; yield return new object[] { 1.2468689889006383, 0.31830988618379073, DoubleCrossPlatformMachineEpsilon }; // expected: (1 / pi) yield return new object[] { 1.3512498725672678, 0.43429448190325226, DoubleCrossPlatformMachineEpsilon }; // expected: (log10(e)) yield return new object[] { 1.5546822754821001, 0.63661977236758126, DoubleCrossPlatformMachineEpsilon }; // expected: (2 / pi) @@ -1664,6 +1744,170 @@ public static IEnumerable RoundToEvenSingle } } + public static IEnumerable SinDouble + { + get + { + yield return new object[] { double.NegativeInfinity, double.NaN, 0.0 }; + yield return new object[] { -3.1415926535897932, -0.0, DoubleCrossPlatformMachineEpsilon }; // value: -(pi) + yield return new object[] { -2.7182818284590452, -0.41078129050290870, DoubleCrossPlatformMachineEpsilon }; // value: -(e) + yield return new object[] { -2.3025850929940457, -0.74398033695749319, DoubleCrossPlatformMachineEpsilon }; // value: -(ln(10)) + yield return new object[] { -1.5707963267948966, -1.0, DoubleCrossPlatformMachineEpsilon * 10 }; // value: -(pi / 2) + yield return new object[] { -1.4426950408889634, -0.99180624439366372, DoubleCrossPlatformMachineEpsilon }; // value: -(log2(e)) + yield return new object[] { -1.4142135623730950, -0.98776594599273553, DoubleCrossPlatformMachineEpsilon }; // value: -(sqrt(2)) + yield return new object[] { -1.1283791670955126, -0.90371945743584630, DoubleCrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) + yield return new object[] { -1.0, -0.84147098480789651, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { -0.78539816339744831, -0.70710678118654752, DoubleCrossPlatformMachineEpsilon }; // value: -(pi / 4), expected: -(1 / sqrt(2)) + yield return new object[] { -0.70710678118654752, -0.64963693908006244, DoubleCrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) + yield return new object[] { -0.69314718055994531, -0.63896127631363480, DoubleCrossPlatformMachineEpsilon }; // value: -(ln(2)) + yield return new object[] { -0.63661977236758134, -0.59448076852482208, DoubleCrossPlatformMachineEpsilon }; // value: -(2 / pi) + yield return new object[] { -0.43429448190325183, -0.42077048331375735, DoubleCrossPlatformMachineEpsilon }; // value: -(log10(e)) + yield return new object[] { -0.31830988618379067, -0.31296179620778659, DoubleCrossPlatformMachineEpsilon }; // value: -(1 / pi) + yield return new object[] { -0.0, -0.0, 0.0 }; + yield return new object[] { double.NaN, double.NaN, 0.0 }; + yield return new object[] { 0.0, 0.0, 0.0 }; + yield return new object[] { 0.31830988618379067, 0.31296179620778659, DoubleCrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { 0.43429448190325183, 0.42077048331375735, DoubleCrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { 0.63661977236758134, 0.59448076852482208, DoubleCrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { 0.69314718055994531, 0.63896127631363480, DoubleCrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { 0.70710678118654752, 0.64963693908006244, DoubleCrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { 0.78539816339744831, 0.70710678118654752, DoubleCrossPlatformMachineEpsilon }; // value: (pi / 4), expected: (1 / sqrt(2)) + yield return new object[] { 1.0, 0.84147098480789651, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { 1.1283791670955126, 0.90371945743584630, DoubleCrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { 1.4142135623730950, 0.98776594599273553, DoubleCrossPlatformMachineEpsilon }; // value: (sqrt(2)) + yield return new object[] { 1.4426950408889634, 0.99180624439366372, DoubleCrossPlatformMachineEpsilon }; // value: (log2(e)) + yield return new object[] { 1.5707963267948966, 1.0, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (pi / 2) + yield return new object[] { 2.3025850929940457, 0.74398033695749319, DoubleCrossPlatformMachineEpsilon }; // value: (ln(10)) + yield return new object[] { 2.7182818284590452, 0.41078129050290870, DoubleCrossPlatformMachineEpsilon }; // value: (e) + yield return new object[] { 3.1415926535897932, 0.0, DoubleCrossPlatformMachineEpsilon }; // value: (pi) + yield return new object[] { double.PositiveInfinity, double.NaN, 0.0 }; + } + } + + public static IEnumerable SinSingle + { + get + { + yield return new object[] { float.NegativeInfinity, float.NaN, 0.0f }; + yield return new object[] { -3.14159265f, -0.0f, SingleCrossPlatformMachineEpsilon }; // value: -(pi) + yield return new object[] { -2.71828183f, -0.410781291f, SingleCrossPlatformMachineEpsilon }; // value: -(e) + yield return new object[] { -2.30258509f, -0.743980337f, SingleCrossPlatformMachineEpsilon }; // value: -(ln(10)) + yield return new object[] { -1.57079633f, -1.0f, SingleCrossPlatformMachineEpsilon * 10 }; // value: -(pi / 2) + yield return new object[] { -1.44269504f, -0.991806244f, SingleCrossPlatformMachineEpsilon }; // value: -(log2(e)) + yield return new object[] { -1.41421356f, -0.987765946f, SingleCrossPlatformMachineEpsilon }; // value: -(sqrt(2)) + yield return new object[] { -1.12837917f, -0.903719457f, SingleCrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) + yield return new object[] { -1.0f, -0.841470985f, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { -0.785398163f, -0.707106781f, SingleCrossPlatformMachineEpsilon }; // value: -(pi / 4), expected: -(1 / sqrt(2)) + yield return new object[] { -0.707106781f, -0.649636939f, SingleCrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) + yield return new object[] { -0.693147181f, -0.638961276f, SingleCrossPlatformMachineEpsilon }; // value: -(ln(2)) + yield return new object[] { -0.636619772f, -0.594480769f, SingleCrossPlatformMachineEpsilon }; // value: -(2 / pi) + yield return new object[] { -0.434294482f, -0.420770483f, SingleCrossPlatformMachineEpsilon }; // value: -(log10(e)) + yield return new object[] { -0.318309886f, -0.312961796f, SingleCrossPlatformMachineEpsilon }; // value: -(1 / pi) + yield return new object[] { -0.0f, -0.0f, 0.0f }; + yield return new object[] { float.NaN, float.NaN, 0.0f }; + yield return new object[] { 0.0f, 0.0f, 0.0f }; + yield return new object[] { 0.318309886f, 0.312961796f, SingleCrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { 0.434294482f, 0.420770483f, SingleCrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { 0.636619772f, 0.594480769f, SingleCrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { 0.693147181f, 0.638961276f, SingleCrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { 0.707106781f, 0.649636939f, SingleCrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { 0.785398163f, 0.707106781f, SingleCrossPlatformMachineEpsilon }; // value: (pi / 4), expected: (1 / sqrt(2)) + yield return new object[] { 1.0f, 0.841470985f, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { 1.12837917f, 0.903719457f, SingleCrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { 1.41421356f, 0.987765946f, SingleCrossPlatformMachineEpsilon }; // value: (sqrt(2)) + yield return new object[] { 1.44269504f, 0.991806244f, SingleCrossPlatformMachineEpsilon }; // value: (log2(e)) + yield return new object[] { 1.57079633f, 1.0f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (pi / 2) + yield return new object[] { 2.30258509f, 0.743980337f, SingleCrossPlatformMachineEpsilon }; // value: (ln(10)) + yield return new object[] { 2.71828183f, 0.410781291f, SingleCrossPlatformMachineEpsilon }; // value: (e) + yield return new object[] { 3.14159265f, 0.0f, SingleCrossPlatformMachineEpsilon }; // value: (pi) + yield return new object[] { float.PositiveInfinity, float.NaN, 0.0f }; + } + } + + public static IEnumerable SinCosDouble + { + get + { + yield return new object[] { double.NegativeInfinity, double.NaN, double.NaN, 0.0, 0.0 }; + yield return new object[] { -1e18, 0.9929693207404051, 0.11837199021871073, 0.0002, 0.002 }; // https://github.com/dotnet/runtime/issues/98204 + yield return new object[] { -3.1415926535897932, -0.0, -1.0, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon * 10 }; // value: -(pi) + yield return new object[] { -2.7182818284590452, -0.41078129050290870, -0.91173391478696510, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: -(e) + yield return new object[] { -2.3025850929940457, -0.74398033695749319, -0.66820151019031295, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: -(ln(10)) + yield return new object[] { -1.5707963267948966, -1.0, 0.0, DoubleCrossPlatformMachineEpsilon * 10, DoubleCrossPlatformMachineEpsilon }; // value: -(pi / 2) + yield return new object[] { -1.4426950408889634, -0.99180624439366372, 0.12775121753523991, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: -(log2(e)) + yield return new object[] { -1.4142135623730950, -0.98776594599273553, 0.15594369476537447, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: -(sqrt(2)) + yield return new object[] { -1.1283791670955126, -0.90371945743584630, 0.42812514788535792, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) + yield return new object[] { -1.0, -0.84147098480789651, 0.54030230586813972, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { -0.78539816339744831, -0.70710678118654752, 0.70710678118654752, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: -(pi / 4), expected_sin: -(1 / sqrt(2)), expected_cos: 1 + yield return new object[] { -0.70710678118654752, -0.64963693908006244, 0.76024459707563015, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) + yield return new object[] { -0.69314718055994531, -0.63896127631363480, 0.76923890136397213, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: -(ln(2)) + yield return new object[] { -0.63661977236758134, -0.59448076852482208, 0.80410982822879171, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: -(2 / pi) + yield return new object[] { -0.43429448190325183, -0.42077048331375735, 0.90716712923909839, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: -(log10(e)) + yield return new object[] { -0.31830988618379067, -0.31296179620778659, 0.94976571538163866, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: -(1 / pi) + yield return new object[] { -0.0, -0.0, 1.0, 0.0, DoubleCrossPlatformMachineEpsilon * 10 }; + yield return new object[] { double.NaN, double.NaN, double.NaN, 0.0, 0.0 }; + yield return new object[] { 0.0, 0.0, 1.0, 0.0, DoubleCrossPlatformMachineEpsilon * 10 }; + yield return new object[] { 0.31830988618379067, 0.31296179620778659, 0.94976571538163866, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { 0.43429448190325183, 0.42077048331375735, 0.90716712923909839, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { 0.63661977236758134, 0.59448076852482208, 0.80410982822879171, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { 0.69314718055994531, 0.63896127631363480, 0.76923890136397213, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { 0.70710678118654752, 0.64963693908006244, 0.76024459707563015, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { 0.78539816339744831, 0.70710678118654752, 0.70710678118654752, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: (pi / 4), expected_sin: (1 / sqrt(2)), expected_cos: 1 + yield return new object[] { 1.0, 0.84147098480789651, 0.54030230586813972, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { 1.1283791670955126, 0.90371945743584630, 0.42812514788535792, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { 1.4142135623730950, 0.98776594599273553, 0.15594369476537447, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: (sqrt(2)) + yield return new object[] { 1.4426950408889634, 0.99180624439366372, 0.12775121753523991, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: (log2(e)) + yield return new object[] { 1.5707963267948966, 1.0, 0.0, DoubleCrossPlatformMachineEpsilon * 10, DoubleCrossPlatformMachineEpsilon }; // value: (pi / 2) + yield return new object[] { 2.3025850929940457, 0.74398033695749319, -0.66820151019031295, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: (ln(10)) + yield return new object[] { 2.7182818284590452, 0.41078129050290870, -0.91173391478696510, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon }; // value: (e) + yield return new object[] { 3.1415926535897932, 0.0, -1.0, DoubleCrossPlatformMachineEpsilon, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (pi) + yield return new object[] { 1e18, -0.9929693207404051, 0.11837199021871073, 0.0002, 0.002 }; // https://github.com/dotnet/runtime/issues/98204 + yield return new object[] { double.PositiveInfinity, double.NaN, double.NaN, 0.0, 0.0 }; + } + } + + public static IEnumerable SinCosSingle + { + get + { + yield return new object[] { float.NegativeInfinity, float.NaN, float.NaN, 0.0f, 0.0f }; + yield return new object[] { -1e8f, -0.931639, -0.36338508, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // https://github.com/dotnet/runtime/issues/98204 + yield return new object[] { -3.14159265f, -0.0f, -1.0f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon * 10 }; // value: -(pi) + yield return new object[] { -2.71828183f, -0.410781291f, -0.911733918f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: -(e) + yield return new object[] { -2.30258509f, -0.743980337f, -0.668201510f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: -(ln(10)) + yield return new object[] { -1.57079633f, -1.0f, 0.0f, SingleCrossPlatformMachineEpsilon * 10, SingleCrossPlatformMachineEpsilon }; // value: -(pi / 2) + yield return new object[] { -1.44269504f, -0.991806244f, 0.127751218f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: -(log2(e)) + yield return new object[] { -1.41421356f, -0.987765946f, 0.155943695f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: -(sqrt(2)) + yield return new object[] { -1.12837917f, -0.903719457f, 0.428125148f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) + yield return new object[] { -1.0f, -0.841470985f, 0.540302306f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { -0.785398163f, -0.707106781f, 0.707106781f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: -(pi / 4), expected_sin: -(1 / sqrt(2)), expected_cos: 1 + yield return new object[] { -0.707106781f, -0.649636939f, 0.760244597f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) + yield return new object[] { -0.693147181f, -0.638961276f, 0.769238901f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: -(ln(2)) + yield return new object[] { -0.636619772f, -0.594480769f, 0.804109828f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: -(2 / pi) + yield return new object[] { -0.434294482f, -0.420770483f, 0.907167129f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: -(log10(e)) + yield return new object[] { -0.318309886f, -0.312961796f, 0.949765715f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: -(1 / pi) + yield return new object[] { -0.0f, -0.0f, 1.0f, 0.0f, SingleCrossPlatformMachineEpsilon * 10 }; + yield return new object[] { float.NaN, float.NaN, float.NaN, 0.0f, 0.0f }; + yield return new object[] { 0.0f, 0.0f, 1.0f, 0.0f, SingleCrossPlatformMachineEpsilon * 10 }; + yield return new object[] { 0.318309886f, 0.312961796f, 0.949765715f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { 0.434294482f, 0.420770483f, 0.907167129f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { 0.636619772f, 0.594480769f, 0.804109828f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { 0.693147181f, 0.638961276f, 0.769238901f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { 0.707106781f, 0.649636939f, 0.760244597f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { 0.785398163f, 0.707106781f, 0.707106781f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: (pi / 4), expected_sin: (1 / sqrt(2)), expected_cos: 1 + yield return new object[] { 1.0f, 0.841470985f, 0.540302306f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { 1.12837917f, 0.903719457f, 0.428125148f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { 1.41421356f, 0.987765946f, 0.155943695f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: (sqrt(2)) + yield return new object[] { 1.44269504f, 0.991806244f, 0.127751218f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: (log2(e)) + yield return new object[] { 1.57079633f, 1.0f, 0.0f, SingleCrossPlatformMachineEpsilon * 10, SingleCrossPlatformMachineEpsilon }; // value: (pi / 2) + yield return new object[] { 2.30258509f, 0.743980337f, -0.668201510f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: (ln(10)) + yield return new object[] { 2.71828183f, 0.410781291f, -0.911733918f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // value: (e) + yield return new object[] { 3.14159265f, 0.0f, -1.0f, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon * 10 }; // value: (pi) + yield return new object[] { 1e8f, 0.931639, -0.36338508, SingleCrossPlatformMachineEpsilon, SingleCrossPlatformMachineEpsilon }; // https://github.com/dotnet/runtime/issues/98204 + yield return new object[] { float.PositiveInfinity, float.NaN, float.NaN, 0.0f, 0.0f }; + } + } + public static IEnumerable TruncateDouble { get diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Cos.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Cos.cs index 36bdcc82e337bb..ff706d02fd78e7 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Cos.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Cos.cs @@ -60,12 +60,24 @@ public static void Cos(ReadOnlySpan x, Span destination) // 3. Reconstruction // Hence, cos(x) = sin(x + pi/2) = (-1)^N * sin(f) - public static bool Vectorizable => typeof(T) == typeof(float) || typeof(T) == typeof(double); + public static bool Vectorizable => (typeof(T) == typeof(float)) + || (typeof(T) == typeof(double)); public static T Invoke(T x) => T.Cos(x); public static Vector128 Invoke(Vector128 x) { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector128.Cos(x.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector128.Cos(x.AsSingle()).As(); + } +#else if (typeof(T) == typeof(float)) { return CosOperatorSingle.Invoke(x.AsSingle()).As(); @@ -75,10 +87,22 @@ public static Vector128 Invoke(Vector128 x) Debug.Assert(typeof(T) == typeof(double)); return CosOperatorDouble.Invoke(x.AsDouble()).As(); } +#endif } public static Vector256 Invoke(Vector256 x) { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector256.Cos(x.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector256.Cos(x.AsSingle()).As(); + } +#else if (typeof(T) == typeof(float)) { return CosOperatorSingle.Invoke(x.AsSingle()).As(); @@ -88,10 +112,22 @@ public static Vector256 Invoke(Vector256 x) Debug.Assert(typeof(T) == typeof(double)); return CosOperatorDouble.Invoke(x.AsDouble()).As(); } +#endif } public static Vector512 Invoke(Vector512 x) { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector512.Cos(x.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector512.Cos(x.AsSingle()).As(); + } +#else if (typeof(T) == typeof(float)) { return CosOperatorSingle.Invoke(x.AsSingle()).As(); @@ -101,9 +137,25 @@ public static Vector512 Invoke(Vector512 x) Debug.Assert(typeof(T) == typeof(double)); return CosOperatorDouble.Invoke(x.AsDouble()).As(); } +#endif } } +#if NET9_0_OR_GREATER + // These are still used by CosPiOperator + + private readonly struct CosOperatorSingle + { + internal const uint MaxVectorizedValue = 0x4A989680u; + internal const uint SignMask = 0x7FFFFFFFu; + } + + private readonly struct CosOperatorDouble + { + internal const ulong SignMask = 0x7FFFFFFFFFFFFFFFul; + internal const ulong MaxVectorizedValue = 0x4160000000000000ul; + } +#else /// float.Cos(x) private readonly struct CosOperatorSingle : IUnaryOperator { @@ -347,5 +399,6 @@ public static Vector512 Invoke(Vector512 x) return (poly.AsUInt64() ^ odd).AsDouble(); } } +#endif } } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.CosPi.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.CosPi.cs index b286a18d0f9424..2db142d2f72908 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.CosPi.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.CosPi.cs @@ -33,13 +33,15 @@ public static void CosPi(ReadOnlySpan x, Span destination) private readonly struct CosPiOperator : IUnaryOperator where T : ITrigonometricFunctions { - public static bool Vectorizable => typeof(T) == typeof(float) || typeof(T) == typeof(double); + public static bool Vectorizable => (typeof(T) == typeof(float)) + || (typeof(T) == typeof(double)); public static T Invoke(T x) => T.CosPi(x); public static Vector128 Invoke(Vector128 x) { Vector128 xpi = x * Vector128.Create(T.Pi); + if (typeof(T) == typeof(float)) { if (Vector128.GreaterThanAny(xpi.AsUInt32() & Vector128.Create(CosOperatorSingle.SignMask), Vector128.Create(CosOperatorSingle.MaxVectorizedValue))) @@ -62,6 +64,7 @@ public static Vector128 Invoke(Vector128 x) public static Vector256 Invoke(Vector256 x) { Vector256 xpi = x * Vector256.Create(T.Pi); + if (typeof(T) == typeof(float)) { if (Vector256.GreaterThanAny(xpi.AsUInt32() & Vector256.Create(CosOperatorSingle.SignMask), Vector256.Create(CosOperatorSingle.MaxVectorizedValue))) @@ -84,6 +87,7 @@ public static Vector256 Invoke(Vector256 x) public static Vector512 Invoke(Vector512 x) { Vector512 xpi = x * Vector512.Create(T.Pi); + if (typeof(T) == typeof(float)) { if (Vector512.GreaterThanAny(xpi.AsUInt32() & Vector512.Create(CosOperatorSingle.SignMask), Vector512.Create(CosOperatorSingle.MaxVectorizedValue))) diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.FloatHelpers.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.FloatHelpers.cs index ec97b9a61af9a7..ecb869c814579e 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.FloatHelpers.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.FloatHelpers.cs @@ -24,5 +24,79 @@ private static Vector256 ApplyScalar(Vector256 double private static Vector512 ApplyScalar(Vector512 doubles) where TOperator : IUnaryOperator => Vector512.Create(ApplyScalar(doubles.GetLower()), ApplyScalar(doubles.GetUpper())); + + private static (Vector128 First, Vector128 Second) Apply2xScalar(Vector128 floats) + where TOperator : IUnaryInputBinaryOutput + { + (float firstRes0, float secondRes0) = TOperator.Invoke(floats[0]); + (float firstRes1, float secondRes1) = TOperator.Invoke(floats[1]); + (float firstRes2, float secondRes2) = TOperator.Invoke(floats[2]); + (float firstRes3, float secondRes3) = TOperator.Invoke(floats[3]); + + return ( + Vector128.Create(firstRes0, firstRes1, firstRes2, firstRes3), + Vector128.Create(secondRes0, secondRes1, secondRes2, secondRes3) + ); + } + + private static (Vector256 First, Vector256 Second) Apply2xScalar(Vector256 floats) + where TOperator : IUnaryInputBinaryOutput + { + (Vector128 firstLower, Vector128 secondLower) = Apply2xScalar(floats.GetLower()); + (Vector128 firstUpper, Vector128 secondUpper) = Apply2xScalar(floats.GetUpper()); + + return ( + Vector256.Create(firstLower, firstUpper), + Vector256.Create(secondLower, secondUpper) + ); + } + + private static (Vector512 First, Vector512 Second) Apply2xScalar(Vector512 floats) + where TOperator : IUnaryInputBinaryOutput + { + (Vector256 firstLower, Vector256 secondLower) = Apply2xScalar(floats.GetLower()); + (Vector256 firstUpper, Vector256 secondUpper) = Apply2xScalar(floats.GetUpper()); + + return ( + Vector512.Create(firstLower, firstUpper), + Vector512.Create(secondLower, secondUpper) + ); + } + + private static (Vector128 First, Vector128 Second) Apply2xScalar(Vector128 doubles) + where TOperator : IUnaryInputBinaryOutput + { + (double firstRes0, double secondRes0) = TOperator.Invoke(doubles[0]); + (double firstRes1, double secondRes1) = TOperator.Invoke(doubles[1]); + + return ( + Vector128.Create(firstRes0, firstRes1), + Vector128.Create(secondRes0, secondRes1) + ); + } + + private static (Vector256 First, Vector256 Second) Apply2xScalar(Vector256 doubles) + where TOperator : IUnaryInputBinaryOutput + { + (Vector128 firstLower, Vector128 secondLower) = Apply2xScalar(doubles.GetLower()); + (Vector128 firstUpper, Vector128 secondUpper) = Apply2xScalar(doubles.GetUpper()); + + return ( + Vector256.Create(firstLower, firstUpper), + Vector256.Create(secondLower, secondUpper) + ); + } + + private static (Vector512 First, Vector512 Second) Apply2xScalar(Vector512 doubles) + where TOperator : IUnaryInputBinaryOutput + { + (Vector256 firstLower, Vector256 secondLower) = Apply2xScalar(doubles.GetLower()); + (Vector256 firstUpper, Vector256 secondUpper) = Apply2xScalar(doubles.GetUpper()); + + return ( + Vector512.Create(firstLower, firstUpper), + Vector512.Create(secondLower, secondUpper) + ); + } } } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Sin.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Sin.cs index 6976a35b3d23a3..02c249f9437a4c 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Sin.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Sin.cs @@ -50,12 +50,24 @@ public static void Sin(ReadOnlySpan x, Span destination) // // The term sin(f) can be approximated by using a polynomial - public static bool Vectorizable => typeof(T) == typeof(float) || typeof(T) == typeof(double); + public static bool Vectorizable => (typeof(T) == typeof(float)) + || (typeof(T) == typeof(double)); public static T Invoke(T x) => T.Sin(x); public static Vector128 Invoke(Vector128 x) { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector128.Sin(x.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector128.Sin(x.AsSingle()).As(); + } +#else if (typeof(T) == typeof(float)) { return SinOperatorSingle.Invoke(x.AsSingle()).As(); @@ -65,10 +77,22 @@ public static Vector128 Invoke(Vector128 x) Debug.Assert(typeof(T) == typeof(double)); return SinOperatorDouble.Invoke(x.AsDouble()).As(); } +#endif } public static Vector256 Invoke(Vector256 x) { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector256.Sin(x.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector256.Sin(x.AsSingle()).As(); + } +#else if (typeof(T) == typeof(float)) { return SinOperatorSingle.Invoke(x.AsSingle()).As(); @@ -78,10 +102,22 @@ public static Vector256 Invoke(Vector256 x) Debug.Assert(typeof(T) == typeof(double)); return SinOperatorDouble.Invoke(x.AsDouble()).As(); } +#endif } public static Vector512 Invoke(Vector512 x) { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector512.Sin(x.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector512.Sin(x.AsSingle()).As(); + } +#else if (typeof(T) == typeof(float)) { return SinOperatorSingle.Invoke(x.AsSingle()).As(); @@ -91,9 +127,25 @@ public static Vector512 Invoke(Vector512 x) Debug.Assert(typeof(T) == typeof(double)); return SinOperatorDouble.Invoke(x.AsDouble()).As(); } +#endif } } +#if NET9_0_OR_GREATER + // These are still used by SinPiOperator + + private readonly struct SinOperatorSingle + { + internal const uint MaxVectorizedValue = 0x49800000u; + internal const uint SignMask = 0x7FFFFFFFu; + } + + private readonly struct SinOperatorDouble + { + internal const ulong SignMask = 0x7FFFFFFFFFFFFFFFul; + internal const ulong MaxVectorizedValue = 0x4160000000000000ul; + } +#else /// float.Sin(x) private readonly struct SinOperatorSingle : IUnaryOperator { @@ -334,5 +386,6 @@ public static Vector512 Invoke(Vector512 x) return (poly.AsUInt64() ^ (x.AsUInt64() & Vector512.Create(~SignMask)) ^ odd).AsDouble(); } } +#endif } } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.SinPi.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.SinPi.cs index 3ee43ecd58c0a9..2b6d86fa8caca3 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.SinPi.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.SinPi.cs @@ -33,13 +33,15 @@ public static void SinPi(ReadOnlySpan x, Span destination) private readonly struct SinPiOperator : IUnaryOperator where T : ITrigonometricFunctions { - public static bool Vectorizable => typeof(T) == typeof(float) || typeof(T) == typeof(double); + public static bool Vectorizable => (typeof(T) == typeof(float)) + || (typeof(T) == typeof(double)); public static T Invoke(T x) => T.SinPi(x); public static Vector128 Invoke(Vector128 x) { Vector128 xpi = x * Vector128.Create(T.Pi); + if (typeof(T) == typeof(float)) { if (Vector128.GreaterThanAny(xpi.AsUInt32() & Vector128.Create(SinOperatorSingle.SignMask), Vector128.Create(SinOperatorSingle.MaxVectorizedValue))) @@ -62,6 +64,7 @@ public static Vector128 Invoke(Vector128 x) public static Vector256 Invoke(Vector256 x) { Vector256 xpi = x * Vector256.Create(T.Pi); + if (typeof(T) == typeof(float)) { if (Vector256.GreaterThanAny(xpi.AsUInt32() & Vector256.Create(SinOperatorSingle.SignMask), Vector256.Create(SinOperatorSingle.MaxVectorizedValue))) @@ -84,6 +87,7 @@ public static Vector256 Invoke(Vector256 x) public static Vector512 Invoke(Vector512 x) { Vector512 xpi = x * Vector512.Create(T.Pi); + if (typeof(T) == typeof(float)) { if (Vector512.GreaterThanAny(xpi.AsUInt32() & Vector512.Create(SinOperatorSingle.SignMask), Vector512.Create(SinOperatorSingle.MaxVectorizedValue))) diff --git a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs index a8f2b8e1b8f487..443d0c64b6f1a0 100644 --- a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs +++ b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs @@ -262,6 +262,8 @@ public static partial class Vector [System.CLSCompliantAttribute(false)] public static System.Numerics.Vector ConvertToUInt64Native(System.Numerics.Vector value) { throw null; } public static System.Numerics.Vector CopySign(System.Numerics.Vector value, System.Numerics.Vector sign) { throw null; } + public static System.Numerics.Vector Cos(System.Numerics.Vector vector) { throw null; } + public static System.Numerics.Vector Cos(System.Numerics.Vector vector) { throw null; } public static System.Numerics.Vector Create(T value) { throw null; } public static System.Numerics.Vector Create(System.ReadOnlySpan values) { throw null; } public static System.Numerics.Vector CreateSequence(T start, T step) { throw null; } @@ -404,6 +406,10 @@ public static partial class Vector public static System.Numerics.Vector ShiftRightLogical(System.Numerics.Vector value, int shiftCount) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Numerics.Vector ShiftRightLogical(System.Numerics.Vector value, int shiftCount) { throw null; } + public static System.Numerics.Vector Sin(System.Numerics.Vector vector) { throw null; } + public static System.Numerics.Vector Sin(System.Numerics.Vector vector) { throw null; } + public static (System.Numerics.Vector Sin, System.Numerics.Vector Cos) SinCos(System.Numerics.Vector vector) { throw null; } + public static (System.Numerics.Vector Sin, System.Numerics.Vector Cos) SinCos(System.Numerics.Vector vector) { throw null; } public static System.Numerics.Vector SquareRoot(System.Numerics.Vector value) { throw null; } [System.CLSCompliantAttribute(false)] public static unsafe void Store(this System.Numerics.Vector source, T* destination) { throw null; } @@ -486,6 +492,7 @@ public partial struct Vector2 : System.IEquatable, Syst public readonly void CopyTo(float[] array) { } public readonly void CopyTo(float[] array, int index) { } public readonly void CopyTo(System.Span destination) { } + public static System.Numerics.Vector2 Cos(System.Numerics.Vector2 vector) { throw null; } public readonly bool TryCopyTo(System.Span destination) { throw null; } public static System.Numerics.Vector2 DegreesToRadians(System.Numerics.Vector2 degrees) { throw null; } public static float Distance(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2) { throw null; } @@ -535,6 +542,8 @@ public readonly void CopyTo(System.Span destination) { } public static System.Numerics.Vector2 Round(System.Numerics.Vector2 vector) { throw null; } public static System.Numerics.Vector2 Round(System.Numerics.Vector2 vector, System.MidpointRounding mode) { throw null; } public static System.Numerics.Vector2 Reflect(System.Numerics.Vector2 vector, System.Numerics.Vector2 normal) { throw null; } + public static System.Numerics.Vector2 Sin(System.Numerics.Vector2 vector) { throw null; } + public static (System.Numerics.Vector2 Sin, System.Numerics.Vector2 Cos) SinCos(System.Numerics.Vector2 vector) { throw null; } public static System.Numerics.Vector2 SquareRoot(System.Numerics.Vector2 value) { throw null; } public static System.Numerics.Vector2 Subtract(System.Numerics.Vector2 left, System.Numerics.Vector2 right) { throw null; } public override readonly string ToString() { throw null; } @@ -582,6 +591,7 @@ public partial struct Vector3 : System.IEquatable, Syst public readonly void CopyTo(float[] array) { } public readonly void CopyTo(float[] array, int index) { } public readonly void CopyTo(System.Span destination) { } + public static System.Numerics.Vector3 Cos(System.Numerics.Vector3 vector) { throw null; } public readonly bool TryCopyTo(System.Span destination) { throw null; } public static System.Numerics.Vector3 Cross(System.Numerics.Vector3 vector1, System.Numerics.Vector3 vector2) { throw null; } public static System.Numerics.Vector3 DegreesToRadians(System.Numerics.Vector3 degrees) { throw null; } @@ -632,6 +642,8 @@ public readonly void CopyTo(System.Span destination) { } public static System.Numerics.Vector3 Reflect(System.Numerics.Vector3 vector, System.Numerics.Vector3 normal) { throw null; } public static System.Numerics.Vector3 Round(System.Numerics.Vector3 vector) { throw null; } public static System.Numerics.Vector3 Round(System.Numerics.Vector3 vector, System.MidpointRounding mode) { throw null; } + public static System.Numerics.Vector3 Sin(System.Numerics.Vector3 vector) { throw null; } + public static (System.Numerics.Vector3 Sin, System.Numerics.Vector3 Cos) SinCos(System.Numerics.Vector3 vector) { throw null; } public static System.Numerics.Vector3 SquareRoot(System.Numerics.Vector3 value) { throw null; } public static System.Numerics.Vector3 Subtract(System.Numerics.Vector3 left, System.Numerics.Vector3 right) { throw null; } public override readonly string ToString() { throw null; } @@ -681,6 +693,7 @@ public partial struct Vector4 : System.IEquatable, Syst public readonly void CopyTo(float[] array) { } public readonly void CopyTo(float[] array, int index) { } public readonly void CopyTo(System.Span destination) { } + public static System.Numerics.Vector4 Cos(System.Numerics.Vector4 vector) { throw null; } public readonly bool TryCopyTo(System.Span destination) { throw null; } public static System.Numerics.Vector4 DegreesToRadians(System.Numerics.Vector4 degrees) { throw null; } public static float Distance(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2) { throw null; } @@ -729,6 +742,8 @@ public readonly void CopyTo(System.Span destination) { } public static System.Numerics.Vector4 RadiansToDegrees(System.Numerics.Vector4 radians) { throw null; } public static System.Numerics.Vector4 Round(System.Numerics.Vector4 vector) { throw null; } public static System.Numerics.Vector4 Round(System.Numerics.Vector4 vector, System.MidpointRounding mode) { throw null; } + public static System.Numerics.Vector4 Sin(System.Numerics.Vector4 vector) { throw null; } + public static (System.Numerics.Vector4 Sin, System.Numerics.Vector4 Cos) SinCos(System.Numerics.Vector4 vector) { throw null; } public static System.Numerics.Vector4 SquareRoot(System.Numerics.Vector4 value) { throw null; } public static System.Numerics.Vector4 Subtract(System.Numerics.Vector4 left, System.Numerics.Vector4 right) { throw null; } public override readonly string ToString() { throw null; } diff --git a/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs b/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs index 8caf901a258bef..dc13ea9c1117b1 100644 --- a/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs @@ -4536,6 +4536,22 @@ private static void TestCreateSequence(T start, T step) } } + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CosDouble), MemberType = typeof(GenericMathTestMemberData))] + public void CosDoubleTest(double value, double expectedResult, double variance) + { + Vector actualResult = Vector.Cos(Vector.Create(value)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CosSingle), MemberType = typeof(GenericMathTestMemberData))] + public void CosSingleTest(float value, float expectedResult, float variance) + { + Vector actualResult = Vector.Cos(Vector.Create(value)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Create(variance)); + } + [Theory] [MemberData(nameof(GenericMathTestMemberData.ExpDouble), MemberType = typeof(GenericMathTestMemberData))] public void ExpDoubleTest(double value, double expectedResult, double variance) @@ -4959,6 +4975,40 @@ public void RoundToEvenSingleTest(float value, float expectedResult) AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); } + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinDouble), MemberType = typeof(GenericMathTestMemberData))] + public void SinDoubleTest(double value, double expectedResult, double variance) + { + Vector actualResult = Vector.Sin(Vector.Create(value)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinSingle), MemberType = typeof(GenericMathTestMemberData))] + public void SinSingleTest(float value, float expectedResult, float variance) + { + Vector actualResult = Vector.Sin(Vector.Create(value)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinCosDouble), MemberType = typeof(GenericMathTestMemberData))] + public void SinCosDoubleTest(double value, double expectedResultSin, double expectedResultCos, double allowedVarianceSin, double allowedVarianceCos) + { + (Vector resultSin, Vector resultCos) = Vector.SinCos(Vector.Create(value)); + AssertEqual(Vector.Create(expectedResultSin), resultSin, Vector.Create(allowedVarianceSin)); + AssertEqual(Vector.Create(expectedResultCos), resultCos, Vector.Create(allowedVarianceCos)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinCosSingle), MemberType = typeof(GenericMathTestMemberData))] + public void SinCosSingleTest(float value, float expectedResultSin, float expectedResultCos, float allowedVarianceSin, float allowedVarianceCos) + { + (Vector resultSin, Vector resultCos) = Vector.SinCos(Vector.Create(value)); + AssertEqual(Vector.Create(expectedResultSin), resultSin, Vector.Create(allowedVarianceSin)); + AssertEqual(Vector.Create(expectedResultCos), resultCos, Vector.Create(allowedVarianceCos)); + } + [Theory] [MemberData(nameof(GenericMathTestMemberData.TruncateDouble), MemberType = typeof(GenericMathTestMemberData))] public void TruncateDoubleTest(double value, double expectedResult) diff --git a/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs b/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs index 3d130d26556092..f2b4a61bbd9bc7 100644 --- a/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs @@ -1299,6 +1299,14 @@ private class EmbeddedVectorObject public Vector2 FieldVector; } + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CosSingle), MemberType = typeof(GenericMathTestMemberData))] + public void CosSingleTest(float value, float expectedResult, float variance) + { + Vector2 actualResult = Vector2.Cos(Vector2.Create(value)); + AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Create(variance)); + } + [Theory] [MemberData(nameof(GenericMathTestMemberData.ExpSingle), MemberType = typeof(GenericMathTestMemberData))] public void ExpSingleTest(float value, float expectedResult, float variance) @@ -1474,6 +1482,23 @@ public void RoundToEvenSingleTest(float value, float expectedResult) AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Zero); } + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinSingle), MemberType = typeof(GenericMathTestMemberData))] + public void SinSingleTest(float value, float expectedResult, float variance) + { + Vector2 actualResult = Vector2.Sin(Vector2.Create(value)); + AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinCosSingle), MemberType = typeof(GenericMathTestMemberData))] + public void SinCosSingleTest(float value, float expectedResultSin, float expectedResultCos, float allowedVarianceSin, float allowedVarianceCos) + { + (Vector2 resultSin, Vector2 resultCos) = Vector2.SinCos(Vector2.Create(value)); + AssertEqual(Vector2.Create(expectedResultSin), resultSin, Vector2.Create(allowedVarianceSin)); + AssertEqual(Vector2.Create(expectedResultCos), resultCos, Vector2.Create(allowedVarianceCos)); + } + [Theory] [MemberData(nameof(GenericMathTestMemberData.TruncateSingle), MemberType = typeof(GenericMathTestMemberData))] public void TruncateSingleTest(float value, float expectedResult) diff --git a/src/libraries/System.Numerics.Vectors/tests/Vector3Tests.cs b/src/libraries/System.Numerics.Vectors/tests/Vector3Tests.cs index 9ec5e504239387..210caf826fb10d 100644 --- a/src/libraries/System.Numerics.Vectors/tests/Vector3Tests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/Vector3Tests.cs @@ -1349,6 +1349,14 @@ private class EmbeddedVectorObject public Vector3 FieldVector; } + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CosSingle), MemberType = typeof(GenericMathTestMemberData))] + public void CosSingleTest(float value, float expectedResult, float variance) + { + Vector3 actualResult = Vector3.Cos(Vector3.Create(value)); + AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Create(variance)); + } + [Theory] [MemberData(nameof(GenericMathTestMemberData.ExpSingle), MemberType = typeof(GenericMathTestMemberData))] public void ExpSingleTest(float value, float expectedResult, float variance) @@ -1524,6 +1532,23 @@ public void RoundToEvenSingleTest(float value, float expectedResult) AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Zero); } + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinSingle), MemberType = typeof(GenericMathTestMemberData))] + public void SinSingleTest(float value, float expectedResult, float variance) + { + Vector3 actualResult = Vector3.Sin(Vector3.Create(value)); + AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinCosSingle), MemberType = typeof(GenericMathTestMemberData))] + public void SinCosSingleTest(float value, float expectedResultSin, float expectedResultCos, float allowedVarianceSin, float allowedVarianceCos) + { + (Vector3 resultSin, Vector3 resultCos) = Vector3.SinCos(Vector3.Create(value)); + AssertEqual(Vector3.Create(expectedResultSin), resultSin, Vector3.Create(allowedVarianceSin)); + AssertEqual(Vector3.Create(expectedResultCos), resultCos, Vector3.Create(allowedVarianceCos)); + } + [Theory] [MemberData(nameof(GenericMathTestMemberData.TruncateSingle), MemberType = typeof(GenericMathTestMemberData))] public void TruncateSingleTest(float value, float expectedResult) diff --git a/src/libraries/System.Numerics.Vectors/tests/Vector4Tests.cs b/src/libraries/System.Numerics.Vectors/tests/Vector4Tests.cs index d1144cdf3e5cd2..74ffeeba94c564 100644 --- a/src/libraries/System.Numerics.Vectors/tests/Vector4Tests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/Vector4Tests.cs @@ -1724,6 +1724,14 @@ public struct Level7 } #pragma warning restore 0169 + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CosSingle), MemberType = typeof(GenericMathTestMemberData))] + public void CosSingleTest(float value, float expectedResult, float variance) + { + Vector4 actualResult = Vector4.Cos(Vector4.Create(value)); + AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Create(variance)); + } + [Theory] [MemberData(nameof(GenericMathTestMemberData.ExpSingle), MemberType = typeof(GenericMathTestMemberData))] public void ExpSingleTest(float value, float expectedResult, float variance) @@ -1899,6 +1907,23 @@ public void RoundToEvenSingleTest(float value, float expectedResult) AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Zero); } + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinSingle), MemberType = typeof(GenericMathTestMemberData))] + public void SinSingleTest(float value, float expectedResult, float variance) + { + Vector4 actualResult = Vector4.Sin(Vector4.Create(value)); + AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinCosSingle), MemberType = typeof(GenericMathTestMemberData))] + public void SinCosSingleTest(float value, float expectedResultSin, float expectedResultCos, float allowedVarianceSin, float allowedVarianceCos) + { + (Vector4 resultSin, Vector4 resultCos) = Vector4.SinCos(Vector4.Create(value)); + AssertEqual(Vector4.Create(expectedResultSin), resultSin, Vector4.Create(allowedVarianceSin)); + AssertEqual(Vector4.Create(expectedResultCos), resultCos, Vector4.Create(allowedVarianceCos)); + } + [Theory] [MemberData(nameof(GenericMathTestMemberData.TruncateSingle), MemberType = typeof(GenericMathTestMemberData))] public void TruncateSingleTest(float value, float expectedResult) diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Quaternion.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Quaternion.cs index f52da0df94f0db..b54bb0c3609403 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Quaternion.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Quaternion.cs @@ -281,11 +281,11 @@ public static Quaternion CreateFromRotationMatrix(Matrix4x4 matrix) /// The resulting quaternion. public static Quaternion CreateFromYawPitchRoll(float yaw, float pitch, float roll) { - // Roll first, about axis the object is facing, then - // pitch upward, then yaw to face into the new heading - (float sr, float cr) = float.SinCos(roll * 0.5f); - (float sp, float cp) = float.SinCos(pitch * 0.5f); - (float sy, float cy) = float.SinCos(yaw * 0.5f); + (Vector3 sin, Vector3 cos) = Vector3.SinCos(Vector3.Create(roll, pitch, yaw) * 0.5f); + + (float sr, float cr) = (sin.X, cos.X); + (float sp, float cp) = (sin.Y, cos.Y); + (float sy, float cy) = (sin.Z, cos.Z); Quaternion result; diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs index f14756fe77723e..69b8ddaac3d3da 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs @@ -537,6 +537,48 @@ public static Vector ConvertToUInt64Native(Vector value) return result; } + internal static Vector Cos(Vector vector) + where T : ITrigonometricFunctions + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = T.Cos(vector.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector Cos(Vector vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.CosDouble, Vector>(vector); + } + else + { + return Cos(vector); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector Cos(Vector vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.CosSingle, Vector, Vector, Vector>(vector); + } + else + { + return Cos(vector); + } + } + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -807,7 +849,7 @@ public static Vector Exp(Vector vector) { if (IsHardwareAccelerated) { - return VectorMath.ExpDouble, Vector, Vector>(vector); + return VectorMath.ExpDouble, Vector>(vector); } else { @@ -2423,6 +2465,92 @@ internal static Vector Round(Vector vector) [CLSCompliant(false)] public static Vector ShiftRightLogical(Vector value, int shiftCount) => value >>> shiftCount; + internal static Vector Sin(Vector vector) + where T : ITrigonometricFunctions + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = T.Sin(vector.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector Sin(Vector vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.SinDouble, Vector>(vector); + } + else + { + return Sin(vector); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector Sin(Vector vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.SinSingle, Vector, Vector, Vector>(vector); + } + else + { + return Sin(vector); + } + } + + internal static (Vector Sin, Vector Cos) SinCos(Vector vector) + where T : ITrigonometricFunctions + { + Unsafe.SkipInit(out Vector sinResult); + Unsafe.SkipInit(out Vector cosResult); + + for (int index = 0; index < Vector.Count; index++) + { + (T sinValue, T cosValue) = T.SinCos(vector.GetElementUnsafe(index)); + sinResult.SetElementUnsafe(index, sinValue); + cosResult.SetElementUnsafe(index, cosValue); + } + + return (sinResult, cosResult); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (Vector Sin, Vector Cos) SinCos(Vector vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.SinCosDouble, Vector>(vector); + } + else + { + return SinCos(vector); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (Vector Sin, Vector Cos) SinCos(Vector vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.SinCosSingle, Vector, Vector, Vector>(vector); + } + else + { + return SinCos(vector); + } + } + /// Computes the square root of a vector on a per-element basis. /// The vector whose square root is to be computed. /// The type of the elements in the vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs index e101a75ea91544..e51501d5102a1e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs @@ -280,6 +280,10 @@ readonly get [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 CopySign(Vector2 value, Vector2 sign) => Vector128.CopySign(value.AsVector128Unsafe(), sign.AsVector128Unsafe()).AsVector2(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Cos(Vector2 vector) => Vector128.Cos(vector.AsVector128()).AsVector2(); + /// Creates a new object whose two elements have the same value. /// The value to assign to all two elements. /// A new whose two elements have the same value. @@ -361,7 +365,7 @@ public static Vector2 Create(ReadOnlySpan values) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 Exp(Vector2 vector) => Vector128.Exp(vector.AsVector128Unsafe()).AsVector2(); + public static Vector2 Exp(Vector2 vector) => Vector128.Exp(vector.AsVector128()).AsVector2(); /// [Intrinsic] @@ -385,11 +389,11 @@ public static Vector2 Create(ReadOnlySpan values) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 Log(Vector2 vector) => Vector128.Log(vector.AsVector128Unsafe()).AsVector2(); + public static Vector2 Log(Vector2 vector) => Vector128.Log(Vector4.Create(vector, 1.0f, 1.0f).AsVector128()).AsVector2(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 Log2(Vector2 vector) => Vector128.Log2(vector.AsVector128Unsafe()).AsVector2(); + public static Vector2 Log2(Vector2 vector) => Vector128.Log2(Vector4.Create(vector, 1.0f, 1.0f).AsVector128()).AsVector2(); /// [Intrinsic] @@ -507,6 +511,18 @@ public static Vector2 Reflect(Vector2 vector, Vector2 normal) [Intrinsic] public static Vector2 Round(Vector2 vector, MidpointRounding mode) => Vector128.Round(vector.AsVector128Unsafe(), mode).AsVector2(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Sin(Vector2 vector) => Vector128.Sin(vector.AsVector128()).AsVector2(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (Vector2 Sin, Vector2 Cos) SinCos(Vector2 vector) + { + (Vector128 sin, Vector128 cos) = Vector128.SinCos(vector.AsVector128()); + return (sin.AsVector2(), cos.AsVector2()); + } + /// Returns a vector whose elements are the square root of each of a specified vector's elements. /// A vector. /// The square root vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs index 8519f382655dec..bc81131e20a497 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs @@ -301,6 +301,10 @@ readonly get [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 CopySign(Vector3 value, Vector3 sign) => Vector128.CopySign(value.AsVector128Unsafe(), sign.AsVector128Unsafe()).AsVector3(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Cos(Vector3 vector) => Vector128.Cos(vector.AsVector128()).AsVector3(); + /// Creates a new object whose three elements have the same value. /// The value to assign to all three elements. /// A new whose three elements have the same value. @@ -418,7 +422,7 @@ public static Vector3 Cross(Vector3 vector1, Vector3 vector2) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 Exp(Vector3 vector) => Vector128.Exp(vector.AsVector128Unsafe()).AsVector3(); + public static Vector3 Exp(Vector3 vector) => Vector128.Exp(vector.AsVector128()).AsVector3(); /// [Intrinsic] @@ -442,11 +446,11 @@ public static Vector3 Cross(Vector3 vector1, Vector3 vector2) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 Log(Vector3 vector) => Vector128.Log(vector.AsVector128Unsafe()).AsVector3(); + public static Vector3 Log(Vector3 vector) => Vector128.Log(Vector4.Create(vector, 1.0f).AsVector128()).AsVector3(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 Log2(Vector3 vector) => Vector128.Log2(vector.AsVector128Unsafe()).AsVector3(); + public static Vector3 Log2(Vector3 vector) => Vector128.Log2(Vector4.Create(vector, 1.0f).AsVector128()).AsVector3(); /// [Intrinsic] @@ -564,6 +568,18 @@ public static Vector3 Reflect(Vector3 vector, Vector3 normal) [Intrinsic] public static Vector3 Round(Vector3 vector, MidpointRounding mode) => Vector128.Round(vector.AsVector128Unsafe(), mode).AsVector3(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Sin(Vector3 vector) => Vector128.Sin(vector.AsVector128()).AsVector3(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (Vector3 Sin, Vector3 Cos) SinCos(Vector3 vector) + { + (Vector128 sin, Vector128 cos) = Vector128.SinCos(vector.AsVector128()); + return (sin.AsVector3(), cos.AsVector3()); + } + /// Returns a vector whose elements are the square root of each of a specified vector's elements. /// A vector. /// The square root vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs index 9c7028520f7623..8dbd1a07f674de 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs @@ -320,6 +320,10 @@ public float this[int index] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 CopySign(Vector4 value, Vector4 sign) => Vector128.CopySign(value.AsVector128(), sign.AsVector128()).AsVector4(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Cos(Vector4 vector) => Vector128.Cos(vector.AsVector128()).AsVector4(); + /// Creates a new object whose four elements have the same value. /// The value to assign to all four elements. /// A new whose four elements have the same value. @@ -557,6 +561,18 @@ public static Vector4 Create(Vector3 vector, float w) [Intrinsic] public static Vector4 Round(Vector4 vector, MidpointRounding mode) => Vector128.Round(vector.AsVector128(), mode).AsVector4(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Sin(Vector4 vector) => Vector128.Sin(vector.AsVector128()).AsVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (Vector4 Sin, Vector4 Cos) SinCos(Vector4 vector) + { + (Vector128 sin, Vector128 cos) = Vector128.SinCos(vector.AsVector128()); + return (sin.AsVector4(), cos.AsVector4()); + } + /// Returns a vector whose elements are the square root of each of a specified vector's elements. /// A vector. /// The square root vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/VectorMath.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/VectorMath.cs deleted file mode 100644 index aea7b92581740b..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/VectorMath.cs +++ /dev/null @@ -1,140 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.CompilerServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; -using System.Runtime.Intrinsics.X86; - -namespace System.Numerics -{ - internal static class VectorMath - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 ConditionalSelectBitwise(Vector128 selector, Vector128 ifTrue, Vector128 ifFalse) - { - // This implementation is based on the DirectX Math Library XMVector4NotEqual method - // https://github.com/microsoft/DirectXMath/blob/master/Inc/DirectXMathVector.inl - - if (AdvSimd.IsSupported) - { - return AdvSimd.BitwiseSelect(selector, ifTrue, ifFalse); - } - else if (Sse.IsSupported) - { - return Sse.Or(Sse.And(ifTrue, selector), Sse.AndNot(selector, ifFalse)); - } - else - { - // Redundant test so we won't prejit remainder of this method on platforms without AdvSimd. - throw new PlatformNotSupportedException(); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 ConditionalSelectBitwise(Vector128 selector, Vector128 ifTrue, Vector128 ifFalse) - { - // This implementation is based on the DirectX Math Library XMVector4NotEqual method - // https://github.com/microsoft/DirectXMath/blob/master/Inc/DirectXMathVector.inl - - if (AdvSimd.IsSupported) - { - return AdvSimd.BitwiseSelect(selector, ifTrue, ifFalse); - } - else if (Sse2.IsSupported) - { - return Sse2.Or(Sse2.And(ifTrue, selector), Sse2.AndNot(selector, ifFalse)); - } - else - { - // Redundant test so we won't prejit remainder of this method on platforms without AdvSimd. - throw new PlatformNotSupportedException(); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool Equal(Vector128 vector1, Vector128 vector2) - { - // This implementation is based on the DirectX Math Library XMVector4Equal method - // https://github.com/microsoft/DirectXMath/blob/master/Inc/DirectXMathVector.inl - - if (AdvSimd.Arm64.IsSupported) - { - Vector128 vResult = AdvSimd.CompareEqual(vector1, vector2).AsUInt32(); - - Vector64 vResult0 = vResult.GetLower().AsByte(); - Vector64 vResult1 = vResult.GetUpper().AsByte(); - - Vector64 vTemp10 = AdvSimd.Arm64.ZipLow(vResult0, vResult1); - Vector64 vTemp11 = AdvSimd.Arm64.ZipHigh(vResult0, vResult1); - - Vector64 vTemp21 = AdvSimd.Arm64.ZipHigh(vTemp10.AsUInt16(), vTemp11.AsUInt16()); - return vTemp21.AsUInt32().GetElement(1) == 0xFFFFFFFF; - } - else if (Sse.IsSupported) - { - return Sse.MoveMask(Sse.CompareNotEqual(vector1, vector2)) == 0; - } - else - { - // Redundant test so we won't prejit remainder of this method on platforms without AdvSimd. - throw new PlatformNotSupportedException(); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 Lerp(Vector128 a, Vector128 b, Vector128 t) - { - // This implementation is based on the DirectX Math Library XMVectorLerp method - // https://github.com/microsoft/DirectXMath/blob/master/Inc/DirectXMathVector.inl - - if (AdvSimd.IsSupported) - { - return AdvSimd.FusedMultiplyAdd(a, AdvSimd.Subtract(b, a), t); - } - else if (Fma.IsSupported) - { - return Fma.MultiplyAdd(Sse.Subtract(b, a), t, a); - } - else if (Sse.IsSupported) - { - return Sse.Add(Sse.Multiply(a, Sse.Subtract(Vector128.Create(1.0f), t)), Sse.Multiply(b, t)); - } - else - { - // Redundant test so we won't prejit remainder of this method on platforms without AdvSimd. - throw new PlatformNotSupportedException(); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool NotEqual(Vector128 vector1, Vector128 vector2) - { - // This implementation is based on the DirectX Math Library XMVector4NotEqual method - // https://github.com/microsoft/DirectXMath/blob/master/Inc/DirectXMathVector.inl - - if (AdvSimd.Arm64.IsSupported) - { - Vector128 vResult = AdvSimd.CompareEqual(vector1, vector2).AsUInt32(); - - Vector64 vResult0 = vResult.GetLower().AsByte(); - Vector64 vResult1 = vResult.GetUpper().AsByte(); - - Vector64 vTemp10 = AdvSimd.Arm64.ZipLow(vResult0, vResult1); - Vector64 vTemp11 = AdvSimd.Arm64.ZipHigh(vResult0, vResult1); - - Vector64 vTemp21 = AdvSimd.Arm64.ZipHigh(vTemp10.AsUInt16(), vTemp11.AsUInt16()); - return vTemp21.AsUInt32().GetElement(1) != 0xFFFFFFFF; - } - else if (Sse.IsSupported) - { - return Sse.MoveMask(Sse.CompareNotEqual(vector1, vector2)) != 0; - } - else - { - // Redundant test so we won't prejit remainder of this method on platforms without AdvSimd. - throw new PlatformNotSupportedException(); - } - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs index 5328f6ce296c5e..8407e91e493fe4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs @@ -824,6 +824,47 @@ public static void CopyTo(this Vector128 vector, Span destination) Unsafe.WriteUnaligned(ref Unsafe.As(ref MemoryMarshal.GetReference(destination)), vector); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Cos(Vector128 vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.CosDouble, Vector128>(vector); + } + else + { + return Create( + Vector64.Cos(vector._lower), + Vector64.Cos(vector._upper) + ); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Cos(Vector128 vector) + { + if (IsHardwareAccelerated) + { + if (Vector256.IsHardwareAccelerated) + { + return VectorMath.CosSingle, Vector128, Vector256, Vector256>(vector); + } + else + { + return VectorMath.CosSingle, Vector128, Vector128, Vector128>(vector); + } + } + else + { + return Create( + Vector64.Cos(vector._lower), + Vector64.Cos(vector._upper) + ); + } + } + /// Creates a new instance with all elements initialized to the specified value. /// The type of the elements in the vector. /// The value that all elements will be initialized to. @@ -1591,7 +1632,7 @@ public static Vector128 Exp(Vector128 vector) { if (IsHardwareAccelerated) { - return VectorMath.ExpDouble, Vector128, Vector128>(vector); + return VectorMath.ExpDouble, Vector128>(vector); } else { @@ -1608,7 +1649,14 @@ public static Vector128 Exp(Vector128 vector) { if (IsHardwareAccelerated) { - return VectorMath.ExpSingle, Vector128, Vector128, Vector128>(vector); + if (Vector256.IsHardwareAccelerated) + { + return VectorMath.ExpSingle, Vector128, Vector256, Vector256>(vector); + } + else + { + return VectorMath.ExpSingle, Vector128, Vector128, Vector128>(vector); + } } else { @@ -1855,7 +1903,14 @@ public static Vector128 Hypot(Vector128 x, Vector128 y) { if (IsHardwareAccelerated) { - return VectorMath.HypotSingle, Vector128>(x, y); + if (Vector256.IsHardwareAccelerated) + { + return VectorMath.HypotSingle, Vector256>(x, y); + } + else + { + return VectorMath.HypotSingle, Vector128>(x, y); + } } else { @@ -3144,6 +3199,94 @@ public static Vector128 Shuffle(Vector128 vector, Vector128 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Sin(Vector128 vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.SinDouble, Vector128>(vector); + } + else + { + return Create( + Vector64.Sin(vector._lower), + Vector64.Sin(vector._upper) + ); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Sin(Vector128 vector) + { + if (IsHardwareAccelerated) + { + if (Vector256.IsHardwareAccelerated) + { + return VectorMath.SinSingle, Vector128, Vector256, Vector256>(vector); + } + else + { + return VectorMath.SinSingle, Vector128, Vector128, Vector128>(vector); + } + } + else + { + return Create( + Vector64.Sin(vector._lower), + Vector64.Sin(vector._upper) + ); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (Vector128 Sin, Vector128 Cos) SinCos(Vector128 vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.SinCosDouble, Vector128>(vector); + } + else + { + (Vector64 sinLower, Vector64 cosLower) = Vector64.SinCos(vector._lower); + (Vector64 sinUpper, Vector64 cosUpper) = Vector64.SinCos(vector._upper); + + return ( + Create(sinLower, sinUpper), + Create(cosLower, cosUpper) + ); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (Vector128 Sin, Vector128 Cos) SinCos(Vector128 vector) + { + if (IsHardwareAccelerated) + { + if (Vector256.IsHardwareAccelerated) + { + return VectorMath.SinCosSingle, Vector128, Vector256, Vector256>(vector); + } + else + { + return VectorMath.SinCosSingle, Vector128, Vector128, Vector128>(vector); + } + } + else + { + (Vector64 sinLower, Vector64 cosLower) = Vector64.SinCos(vector._lower); + (Vector64 sinUpper, Vector64 cosUpper) = Vector64.SinCos(vector._upper); + + return ( + Create(sinLower, sinUpper), + Create(cosLower, cosUpper) + ); + } + } + /// Computes the square root of a vector on a per-element basis. /// The type of the elements in the vector. /// The vector whose square root is to be computed. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs index c85772d3f59e51..a84129376b07d2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs @@ -663,6 +663,47 @@ public static void CopyTo(this Vector256 vector, Span destination) Unsafe.WriteUnaligned(ref Unsafe.As(ref MemoryMarshal.GetReference(destination)), vector); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 Cos(Vector256 vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.CosDouble, Vector256>(vector); + } + else + { + return Create( + Vector128.Cos(vector._lower), + Vector128.Cos(vector._upper) + ); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 Cos(Vector256 vector) + { + if (IsHardwareAccelerated) + { + if (Vector512.IsHardwareAccelerated) + { + return VectorMath.CosSingle, Vector256, Vector512, Vector512>(vector); + } + else + { + return VectorMath.CosSingle, Vector256, Vector256, Vector256>(vector); + } + } + else + { + return Create( + Vector128.Cos(vector._lower), + Vector128.Cos(vector._upper) + ); + } + } + /// Creates a new instance with all elements initialized to the specified value. /// The type of the elements in the vector. /// The value that all elements will be initialized to. @@ -1509,7 +1550,7 @@ public static Vector256 Exp(Vector256 vector) { if (IsHardwareAccelerated) { - return VectorMath.ExpDouble, Vector256, Vector256>(vector); + return VectorMath.ExpDouble, Vector256>(vector); } else { @@ -1526,7 +1567,14 @@ public static Vector256 Exp(Vector256 vector) { if (IsHardwareAccelerated) { - return VectorMath.ExpSingle, Vector256, Vector256, Vector256>(vector); + if (Vector512.IsHardwareAccelerated) + { + return VectorMath.ExpSingle, Vector256, Vector512, Vector512>(vector); + } + else + { + return VectorMath.ExpSingle, Vector256, Vector256, Vector256>(vector); + } } else { @@ -1771,7 +1819,14 @@ public static Vector256 Hypot(Vector256 x, Vector256 y) { if (IsHardwareAccelerated) { - return VectorMath.HypotSingle, Vector256>(x, y); + if (Vector512.IsHardwareAccelerated) + { + return VectorMath.HypotSingle, Vector512>(x, y); + } + else + { + return VectorMath.HypotSingle, Vector256>(x, y); + } } else { @@ -3027,6 +3082,94 @@ public static Vector256 Shuffle(Vector256 vector, Vector256 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 Sin(Vector256 vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.SinDouble, Vector256>(vector); + } + else + { + return Create( + Vector128.Sin(vector._lower), + Vector128.Sin(vector._upper) + ); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 Sin(Vector256 vector) + { + if (IsHardwareAccelerated) + { + if (Vector512.IsHardwareAccelerated) + { + return VectorMath.SinSingle, Vector256, Vector512, Vector512>(vector); + } + else + { + return VectorMath.SinSingle, Vector256, Vector256, Vector256>(vector); + } + } + else + { + return Create( + Vector128.Sin(vector._lower), + Vector128.Sin(vector._upper) + ); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (Vector256 Sin, Vector256 Cos) SinCos(Vector256 vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.SinCosDouble, Vector256>(vector); + } + else + { + (Vector128 sinLower, Vector128 cosLower) = Vector128.SinCos(vector._lower); + (Vector128 sinUpper, Vector128 cosUpper) = Vector128.SinCos(vector._upper); + + return ( + Create(sinLower, sinUpper), + Create(cosLower, cosUpper) + ); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (Vector256 Sin, Vector256 Cos) SinCos(Vector256 vector) + { + if (IsHardwareAccelerated) + { + if (Vector512.IsHardwareAccelerated) + { + return VectorMath.SinCosSingle, Vector256, Vector512, Vector512>(vector); + } + else + { + return VectorMath.SinCosSingle, Vector256, Vector256, Vector256>(vector); + } + } + else + { + (Vector128 sinLower, Vector128 cosLower) = Vector128.SinCos(vector._lower); + (Vector128 sinUpper, Vector128 cosUpper) = Vector128.SinCos(vector._upper); + + return ( + Create(sinLower, sinUpper), + Create(cosLower, cosUpper) + ); + } + } + /// Computes the square root of a vector on a per-element basis. /// The type of the elements in the vector. /// The vector whose square root is to be computed. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs index bc7e32e1e5f747..092b041b84aebe 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs @@ -589,6 +589,40 @@ public static void CopyTo(this Vector512 vector, Span destination) Unsafe.WriteUnaligned(ref Unsafe.As(ref MemoryMarshal.GetReference(destination)), vector); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 Cos(Vector512 vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.CosDouble, Vector512>(vector); + } + else + { + return Create( + Vector256.Cos(vector._lower), + Vector256.Cos(vector._upper) + ); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 Cos(Vector512 vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.CosSingle, Vector512, Vector512, Vector512>(vector); + } + else + { + return Create( + Vector256.Cos(vector._lower), + Vector256.Cos(vector._upper) + ); + } + } + /// Creates a new instance with all elements initialized to the specified value. /// The type of the elements in the vector. /// The value that all elements will be initialized to. @@ -1572,7 +1606,7 @@ public static Vector512 Exp(Vector512 vector) { if (IsHardwareAccelerated) { - return VectorMath.ExpDouble, Vector512, Vector512>(vector); + return VectorMath.ExpDouble, Vector512>(vector); } else { @@ -3089,6 +3123,80 @@ public static Vector512 Shuffle(Vector512 vector, Vector512 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 Sin(Vector512 vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.SinDouble, Vector512>(vector); + } + else + { + return Create( + Vector256.Sin(vector._lower), + Vector256.Sin(vector._upper) + ); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 Sin(Vector512 vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.SinSingle, Vector512, Vector512, Vector512>(vector); + } + else + { + return Create( + Vector256.Sin(vector._lower), + Vector256.Sin(vector._upper) + ); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (Vector512 Sin, Vector512 Cos) SinCos(Vector512 vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.SinCosDouble, Vector512>(vector); + } + else + { + (Vector256 sinLower, Vector256 cosLower) = Vector256.SinCos(vector._lower); + (Vector256 sinUpper, Vector256 cosUpper) = Vector256.SinCos(vector._upper); + + return ( + Create(sinLower, sinUpper), + Create(cosLower, cosUpper) + ); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (Vector512 Sin, Vector512 Cos) SinCos(Vector512 vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.SinCosSingle, Vector512, Vector512, Vector512>(vector); + } + else + { + (Vector256 sinLower, Vector256 cosLower) = Vector256.SinCos(vector._lower); + (Vector256 sinUpper, Vector256 cosUpper) = Vector256.SinCos(vector._upper); + + return ( + Create(sinLower, sinUpper), + Create(cosLower, cosUpper) + ); + } + } + /// Computes the square root of a vector on a per-element basis. /// The type of the elements in the vector. /// The vector whose square root is to be computed. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs index 5e0bcb38a4d765..dfd95f4021df1a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs @@ -607,6 +607,59 @@ public static void CopyTo(this Vector64 vector, Span destination) Unsafe.WriteUnaligned(ref Unsafe.As(ref MemoryMarshal.GetReference(destination)), vector); } + internal static Vector64 Cos(Vector64 vector) + where T : ITrigonometricFunctions + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + T value = T.Cos(vector.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + + /// Computes the cos of each element in a vector. + /// The vector that will have its Cos computed. + /// A vector whose elements are the cos of the elements in . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 Cos(Vector64 vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.CosDouble, Vector64>(vector); + } + else + { + return Cos(vector); + } + } + + /// Computes the cos of each element in a vector. + /// The vector that will have its Cos computed. + /// A vector whose elements are the cos of the elements in . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 Cos(Vector64 vector) + { + if (IsHardwareAccelerated) + { + if (Vector128.IsHardwareAccelerated) + { + return VectorMath.CosSingle, Vector64, Vector128, Vector128>(vector); + } + else + { + return VectorMath.CosSingle, Vector64, Vector64, Vector64>(vector); + } + } + else + { + return Cos(vector); + } + } + /// Creates a new instance with all elements initialized to the specified value. /// The type of the elements in the vector. /// The value that all elements will be initialized to. @@ -1248,7 +1301,7 @@ public static Vector64 Exp(Vector64 vector) { if (IsHardwareAccelerated) { - return VectorMath.ExpDouble, Vector64, Vector64>(vector); + return VectorMath.ExpDouble, Vector64>(vector); } else { @@ -1264,7 +1317,14 @@ public static Vector64 Exp(Vector64 vector) { if (IsHardwareAccelerated) { - return VectorMath.ExpSingle, Vector64, Vector64, Vector64>(vector); + if (Vector128.IsHardwareAccelerated) + { + return VectorMath.ExpSingle, Vector64, Vector128, Vector128>(vector); + } + else + { + return VectorMath.ExpSingle, Vector64, Vector64, Vector64>(vector); + } } else { @@ -1574,7 +1634,14 @@ public static Vector64 Hypot(Vector64 x, Vector64 y) { if (IsHardwareAccelerated) { - return VectorMath.HypotSingle, Vector64>(x, y); + if (Vector128.IsHardwareAccelerated) + { + return VectorMath.HypotSingle, Vector128>(x, y); + } + else + { + return VectorMath.HypotSingle, Vector64>(x, y); + } } else { @@ -3002,6 +3069,114 @@ public static Vector64 Shuffle(Vector64 vector, Vector64 indi return result; } + internal static Vector64 Sin(Vector64 vector) + where T : ITrigonometricFunctions + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + T value = T.Sin(vector.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + + /// Computes the sin of each element in a vector. + /// The vector that will have its Sin computed. + /// A vector whose elements are the sin of the elements in . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 Sin(Vector64 vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.SinDouble, Vector64>(vector); + } + else + { + return Sin(vector); + } + } + + /// Computes the sin of each element in a vector. + /// The vector that will have its Sin computed. + /// A vector whose elements are the sin of the elements in . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 Sin(Vector64 vector) + { + if (IsHardwareAccelerated) + { + if (Vector128.IsHardwareAccelerated) + { + return VectorMath.SinSingle, Vector64, Vector128, Vector128>(vector); + } + else + { + return VectorMath.SinSingle, Vector64, Vector64, Vector64>(vector); + } + } + else + { + return Sin(vector); + } + } + + internal static (Vector64 Sin, Vector64 Cos) SinCos(Vector64 vector) + where T : ITrigonometricFunctions + { + Unsafe.SkipInit(out Vector64 sinResult); + Unsafe.SkipInit(out Vector64 cosResult); + + for (int index = 0; index < Vector64.Count; index++) + { + (T sinValue, T cosValue) = T.SinCos(vector.GetElementUnsafe(index)); + sinResult.SetElementUnsafe(index, sinValue); + cosResult.SetElementUnsafe(index, cosValue); + } + + return (sinResult, cosResult); + } + + /// Computes the sincos of each element in a vector. + /// The vector that will have its SinCos computed. + /// A vector whose elements are the sincos of the elements in . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (Vector64 Sin, Vector64 Cos) SinCos(Vector64 vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.SinCosDouble, Vector64>(vector); + } + else + { + return SinCos(vector); + } + } + + /// Computes the sincos of each element in a vector. + /// The vector that will have its SinCos computed. + /// A vector whose elements are the sincos of the elements in . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (Vector64 Sin, Vector64 Cos) SinCos(Vector64 vector) + { + if (IsHardwareAccelerated) + { + if (Vector128.IsHardwareAccelerated) + { + return VectorMath.SinCosSingle, Vector64, Vector128, Vector128>(vector); + } + else + { + return VectorMath.SinCosSingle, Vector64, Vector64, Vector64>(vector); + } + } + else + { + return SinCos(vector); + } + } + /// Computes the square root of a vector on a per-element basis. /// The type of the elements in the vector. /// The vector whose square root is to be computed. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs index fbe07cc62a9af2..bc0d1b7c82f846 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs @@ -12,6 +12,305 @@ namespace System.Runtime.Intrinsics { internal static unsafe class VectorMath { + public static TVectorDouble CosDouble(TVectorDouble x) + where TVectorDouble : unmanaged, ISimdVector + where TVectorInt64 : unmanaged, ISimdVector + { + // This code is based on `cos` from amd/aocl-libm-ose + // Copyright (C) 2008-2022 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 + + // Implementation Notes + // --------------------- + // checks for special cases + // if ( ux = infinity) raise overflow exception and return x + // if x is NaN then raise invalid FP operation exception and return x. + // + // 1. Argument reduction + // if |x| > 5e5 then + // __amd_remainder_piby2(x, &r, &rr, ®ion) + // else + // Argument reduction + // Let z = |x| * 2/pi + // z = dn + r, where dn = round(z) + // rhead = dn * pi/2_head + // rtail = dn * pi/2_tail + // r = z – dn = |x| - rhead – rtail + // expdiff = exp(dn) – exp(r) + // if(expdiff) > 15) + // rtail = |x| - dn*pi/2_tail2 + // r = |x| - dn*pi/2_head - dn*pi/2_tail1 - dn*pi/2_tail2 - (((rhead + rtail) – rhead )-rtail) + // rr = (|x| – rhead) – r + rtail + // + // 2. Polynomial approximation + // if(dn is even) + // rr = rr * r; + // x4 = x2 * x2; + // s = 0.5 * x2; + // t = s - 1.0; + // poly = x4 * (C1 + x2 * (C2 + x2 * (C3 + x2 * (C4 + x2 * (C5 + x2 * x6))))) + // r = (((1.0 + t) - s) - rr) + poly – t + // else + // x3 = x2 * r + // poly = S2 + (r2 * (S3 + (r2 * (S4 + (r2 * (S5 + S6 * r2)))))) + // r = r - ((x2 * (0.5*rr - x3 * poly)) - rr) - S1 * x3 + // if((sign + 1) & 2) + // return r + // else + // return -r; + // + // if |x| < pi/4 && |x| > 2.0^(-13) + // cos(x) = 1.0 + x*x * (-0.5 + (C1*x*x + (C2*x*x + (C3*x*x + // + (C4*x*x + (C5*x*x + C6*x*x)))))) + // + // if |x| < 2.0^(-13) && |x| > 2.0^(-27) + // cos(x) = 1.0 - x*x*0.5;; + // + // else return 1.0 + + const long ARG_HUGE = 0x415312D000000000; // 5e6 + const long ARG_LARGE = 0x3FE921FB54442D18; // PI / 4 + const long ARG_SMALL = 0x3F20000000000000; // 2^-13 + const long ARG_SMALLER = 0x3E40000000000000; // 2^-27 + + TVectorDouble ax = TVectorDouble.Abs(x); + TVectorInt64 ux = Unsafe.BitCast(ax); + + TVectorDouble result; + + if (TVectorInt64.LessThanAll(ux, TVectorInt64.Create(ARG_LARGE + 1))) + { + // We must be a finite value: (pi / 4) >= |x| + TVectorDouble x2 = x * x; + + if (TVectorInt64.GreaterThanAny(ux, TVectorInt64.Create(ARG_SMALL - 1))) + { + // at least one element is: |x| >= 2^-13 + result = TVectorDouble.MultiplyAddEstimate( + TVectorDouble.MultiplyAddEstimate( + CosDoublePoly(x), + x2, + TVectorDouble.Create(-0.5)), + x2, + TVectorDouble.One + ); + } + else + { + result = TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(-0.5), x2, TVectorDouble.One); + } + } + else if (TVectorInt64.LessThanAll(ux, TVectorInt64.Create(ARG_HUGE))) + { + // at least one element is: |x| > (pi / 4) -or- infinite -or- nan + (TVectorDouble r, TVectorDouble rr, TVectorInt64 region) = SinCosReduce(ax); + + TVectorDouble sin = SinDoubleLarge(r, rr); + TVectorDouble cos = CosDoubleLarge(r, rr); + + result = TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.Equals(region & TVectorInt64.One, TVectorInt64.Zero)), + cos, // region 0 or 2 + sin // region 1 or 3 + ); + + result = TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.Equals((region + TVectorInt64.One) & TVectorInt64.Create(2), TVectorInt64.Zero)), + +result, // region 0 or 3 + -result // region 1 or 2 + ); + } + else + { + return ScalarFallback(x); + } + + return TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.GreaterThan(ux, TVectorInt64.Create(ARG_SMALLER - 1))), + result, // for elements: |x| >= 2^-27, infinity, or NaN + TVectorDouble.One // for elements: 2^-27 > |x| + ); + + static TVectorDouble ScalarFallback(TVectorDouble x) + { + TVectorDouble result = TVectorDouble.Zero; + + for (int i = 0; i < TVectorDouble.Count; i++) + { + double scalar = double.Cos(x[i]); + result = result.WithElement(i, scalar); + } + + return result; + } + } + + public static TVectorSingle CosSingle(TVectorSingle x) + where TVectorSingle : unmanaged, ISimdVector + where TVectorInt32 : unmanaged, ISimdVector + where TVectorDouble : unmanaged, ISimdVector + where TVectorInt64 : unmanaged, ISimdVector + { + // This code is based on `cosf` from amd/aocl-libm-ose + // Copyright (C) 2008-2022 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 + + // Implementation Notes + // --------------------- + // Checks for special cases + // if ( ux = infinity) raise overflow exception and return x + // if x is NaN then raise invalid FP operation exception and return x. + // + // 1. Argument reduction + // if |x| > 5e5 then + // __amd_remainder_piby2d2f((uint64_t)x, &r, ®ion) + // else + // Argument reduction + // Let z = |x| * 2/pi + // z = dn + r, where dn = round(z) + // rhead = dn * pi/2_head + // rtail = dn * pi/2_tail + // r = z – dn = |x| - rhead – rtail + // expdiff = exp(dn) – exp(r) + // if(expdiff) > 15) + // rtail = |x| - dn*pi/2_tail2 + // r = |x| - dn*pi/2_head - dn*pi/2_tail1 + // - dn*pi/2_tail2 - (((rhead + rtail) – rhead )-rtail) + // + // 2. Polynomial approximation + // if(dn is even) + // x4 = x2 * x2; + // s = 0.5 * x2; + // t = 1.0 - s; + // poly = x4 * (C1 + x2 * (C2 + x2 * (C3 + x2 * C4 ))) + // r = t + poly + // else + // x3 = x2 * r + // poly = x3 * (S1 + x2 * (S2 + x2 * (S3 + x2 * S4))) + // r = r + poly + // if((sign + 1) & 2) + // return r + // else + // return -r; + // + // if |x| < pi/4 && |x| > 2.0^(-13) + // r = 0.5 * x2; + // t = 1 - r; + // cos(x) = t + ((1.0 - t) - r) + (x*x * (x*x * C1 + C2*x*x + C3*x*x + // + C4*x*x +x*x*C5 + x*x*C6))) + // + // if |x| < 2.0^(-13) && |x| > 2.0^(-27) + // cos(x) = 1.0 - x*x*0.5;; + // + // else return 1.0 + + const int ARG_HUGE = 0x4A989680; // 5e6 + const int ARG_LARGE = 0x3F490FDB; // PI / 4 + const int ARG_SMALL = 0x3C000000; // 2^-13 + const int ARG_SMALLER = 0x39000000; // 2^-27 + + TVectorSingle ax = TVectorSingle.Abs(x); + TVectorInt32 ux = Unsafe.BitCast(ax); + + TVectorSingle result; + + if (TVectorInt32.LessThanAll(ux, TVectorInt32.Create(ARG_LARGE + 1))) + { + // We must be a finite value: (pi / 4) >= |x| + + if (TVectorInt32.GreaterThanAny(ux, TVectorInt32.Create(ARG_SMALL - 1))) + { + // at least one element is: |x| >= 2^-13 + + if (TVectorSingle.Count == TVectorDouble.Count) + { + result = Narrow( + CosSingleSmall(Widen(x)) + ); + } + else + { + result = Narrow( + CosSingleSmall(WidenLower(x)), + CosSingleSmall(WidenUpper(x)) + ); + } + } + else + { + // at least one element is: 2^-13 > |x| + TVectorSingle x2 = x * x; + result = TVectorSingle.MultiplyAddEstimate(TVectorSingle.Create(-0.5f), x2, TVectorSingle.One); + } + } + else if (TVectorInt32.LessThanAll(ux, TVectorInt32.Create(ARG_HUGE))) + { + // at least one element is: |x| > (pi / 4) -or- infinite -or- nan + + if (TVectorSingle.Count == TVectorDouble.Count) + { + result = Narrow( + CoreImpl(Widen(ax)) + ); + } + else + { + result = Narrow( + CoreImpl(WidenLower(ax)), + CoreImpl(WidenUpper(ax)) + ); + } + } + else + { + return ScalarFallback(x); + } + + return TVectorSingle.ConditionalSelect( + Unsafe.BitCast(TVectorInt32.GreaterThan(ux, TVectorInt32.Create(ARG_SMALLER - 1))), + result, // for elements: |x| >= 2^-27, infinity, or NaN + TVectorSingle.One // for elements: 2^-27 > |x| + ); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static TVectorDouble CoreImpl(TVectorDouble ax) + { + (TVectorDouble r, _, TVectorInt64 region) = SinCosReduce(ax); + + TVectorDouble sin = SinSinglePoly(r); + TVectorDouble cos = CosSingleLarge(r); + + TVectorDouble result = TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.Equals(region & TVectorInt64.One, TVectorInt64.Zero)), + cos, // region 0 or 2 + sin // region 1 or 3 + ); + + return TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.Equals((region + TVectorInt64.One) & TVectorInt64.Create(2), TVectorInt64.Zero)), + +result, // region 0 or 3 + -result // region 1 or 2 + ); + } + + static TVectorSingle ScalarFallback(TVectorSingle x) + { + TVectorSingle result = TVectorSingle.Zero; + + for (int i = 0; i < TVectorSingle.Count; i++) + { + float scalar = float.Cos(x[i]); + result = result.WithElement(i, scalar); + } + + return result; + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TVector CopySign(TVector value, TVector sign) where TVector : unmanaged, ISimdVector @@ -50,7 +349,7 @@ public static TVector DegreesToRadians(TVector degrees) return (degrees * TVector.Create(T.Pi)) / TVector.Create(T.CreateTruncating(180)); } - public static TVectorDouble ExpDouble(TVectorDouble x) + public static TVectorDouble ExpDouble(TVectorDouble x) where TVectorDouble : unmanaged, ISimdVector where TVectorUInt64 : unmanaged, ISimdVector { @@ -153,7 +452,7 @@ public static TVectorDouble ExpDouble((n + TVectorUInt64.Create(V_DP64_BIAS)) << 52); + TVectorDouble result = poly * Unsafe.BitCast((n + TVectorUInt64.Create(V_DP64_BIAS)) << 52); // Check if -709 < vx < 709 if (TVectorUInt64.GreaterThanAny(Unsafe.BitCast(TVectorDouble.Abs(x)), TVectorUInt64.Create(V_ARG_MAX))) @@ -161,17 +460,17 @@ public static TVectorDouble ExpDouble V_EXPF_MAX) ? double.PositiveInfinity : x TVectorDouble infinityMask = TVectorDouble.GreaterThan(x, TVectorDouble.Create(V_EXPF_MAX)); - ret = TVectorDouble.ConditionalSelect( + result = TVectorDouble.ConditionalSelect( infinityMask, TVectorDouble.Create(double.PositiveInfinity), - ret + result ); // (x < V_EXPF_MIN) ? 0 : x - ret = TVectorDouble.AndNot(ret, TVectorDouble.LessThan(x, TVectorDouble.Create(V_EXPF_MIN))); + result = TVectorDouble.AndNot(result, TVectorDouble.LessThan(x, TVectorDouble.Create(V_EXPF_MIN))); } - return ret; + return result; } public static TVectorSingle ExpSingle(TVectorSingle x) @@ -224,71 +523,21 @@ public static TVectorSingle ExpSingle(x); - - // x * (64.0 / ln(2)) - TVectorDouble v_tbl_ln2 = TVectorDouble.Create(V_TBL_LN2); - - TVectorDouble zl = xl * v_tbl_ln2; - TVectorDouble zu = xu * v_tbl_ln2; - - TVectorDouble v_expf_huge = TVectorDouble.Create(V_EXPF_HUGE); - - TVectorDouble dnl = zl + v_expf_huge; - TVectorDouble dnu = zu + v_expf_huge; - - // n = (int)z - TVectorUInt64 nl = Unsafe.BitCast(dnl); - TVectorUInt64 nu = Unsafe.BitCast(dnu); - - // dn = (double)n - dnl -= v_expf_huge; - dnu -= v_expf_huge; - - // r = z - dn - TVectorDouble c1 = TVectorDouble.Create(C1); - TVectorDouble c2 = TVectorDouble.Create(C2); - TVectorDouble c3 = TVectorDouble.Create(C3); - TVectorDouble c4 = TVectorDouble.Create(C4); - TVectorDouble c5 = TVectorDouble.Create(C5); - TVectorDouble c6 = TVectorDouble.Create(C6); - - TVectorDouble rl = zl - dnl; - - TVectorDouble rl2 = rl * rl; - TVectorDouble rl4 = rl2 * rl2; - - TVectorDouble polyl = TVectorDouble.MultiplyAddEstimate( - rl4, - TVectorDouble.MultiplyAddEstimate(c6, rl, c5), - TVectorDouble.MultiplyAddEstimate( - rl2, - TVectorDouble.MultiplyAddEstimate(c4, rl, c3), - TVectorDouble.MultiplyAddEstimate(c2, rl, c1) - ) - ); - - TVectorDouble ru = zu - dnu; - - TVectorDouble ru2 = ru * ru; - TVectorDouble ru4 = ru2 * ru2; - - TVectorDouble polyu = TVectorDouble.MultiplyAddEstimate( - ru4, - TVectorDouble.MultiplyAddEstimate(c6, ru, c5), - TVectorDouble.MultiplyAddEstimate( - ru2, - TVectorDouble.MultiplyAddEstimate(c4, ru, c3), - TVectorDouble.MultiplyAddEstimate(c2, ru, c1) - ) - ); + TVectorSingle result; - // result = (float)(poly + (n << 52)) - TVectorSingle ret = Narrow( - Unsafe.BitCast(Unsafe.BitCast(polyl) + (nl << 52)), - Unsafe.BitCast(Unsafe.BitCast(polyu) + (nu << 52)) - ); + if (TVectorSingle.Count == TVectorDouble.Count) + { + result = Narrow( + CoreImpl(Widen(x)) + ); + } + else + { + result = Narrow( + CoreImpl(WidenLower(x)), + CoreImpl(WidenUpper(x)) + ); + } // Check if -103 < |x| < 88 if (TVectorUInt32.GreaterThanAny(Unsafe.BitCast(TVectorSingle.Abs(x)), TVectorUInt32.Create(V_ARG_MAX))) @@ -296,17 +545,49 @@ public static TVectorSingle ExpSingle V_EXPF_MAX) ? float.PositiveInfinity : x TVectorSingle infinityMask = TVectorSingle.GreaterThan(x, TVectorSingle.Create(V_EXPF_MAX)); - ret = TVectorSingle.ConditionalSelect( + result = TVectorSingle.ConditionalSelect( infinityMask, TVectorSingle.Create(float.PositiveInfinity), - ret + result ); // (x < V_EXPF_MIN) ? 0 : x - ret = TVectorSingle.AndNot(ret, TVectorSingle.LessThan(x, TVectorSingle.Create(V_EXPF_MIN))); + result = TVectorSingle.AndNot(result, TVectorSingle.LessThan(x, TVectorSingle.Create(V_EXPF_MIN))); } - return ret; + return result; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static TVectorDouble CoreImpl(TVectorDouble x) + { + // x * (64.0 / ln(2)) + TVectorDouble z = x * TVectorDouble.Create(V_TBL_LN2); + + TVectorDouble v_expf_huge = TVectorDouble.Create(V_EXPF_HUGE); + TVectorDouble dn = z + v_expf_huge; + + // n = (int)z + TVectorUInt64 n = Unsafe.BitCast(dn); + + // r = z - n + TVectorDouble r = z - (dn - v_expf_huge); + + TVectorDouble r2 = r * r; + TVectorDouble r4 = r2 * r2; + + TVectorDouble poly = TVectorDouble.MultiplyAddEstimate( + r4, + TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(C6), r, TVectorDouble.Create(C5)), + TVectorDouble.MultiplyAddEstimate( + r2, + TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(C4), r, TVectorDouble.Create(C3)), + TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(C2), r, TVectorDouble.Create(C1)) + ) + ); + + // result = poly + (n << 52) + return Unsafe.BitCast(Unsafe.BitCast(poly) + (n << 52)); + } } public static TVectorDouble HypotDouble(TVectorDouble x, TVectorDouble y) @@ -455,13 +736,21 @@ public static TVectorSingle HypotSingle(TVectorSin TVectorSingle infinityMask = TVectorSingle.IsPositiveInfinity(ax) | TVectorSingle.IsPositiveInfinity(ay); TVectorSingle nanMask = TVectorSingle.IsNaN(ax) | TVectorSingle.IsNaN(ay); - (TVectorDouble xxLower, TVectorDouble xxUpper) = Widen(ax); - (TVectorDouble yyLower, TVectorDouble yyUpper) = Widen(ay); + TVectorSingle result; - TVectorSingle result = Narrow( - TVectorDouble.Sqrt(TVectorDouble.MultiplyAddEstimate(xxLower, xxLower, yyLower * yyLower)), - TVectorDouble.Sqrt(TVectorDouble.MultiplyAddEstimate(xxUpper, xxUpper, yyUpper * yyUpper)) - ); + if (TVectorSingle.Count == TVectorDouble.Count) + { + result = Narrow( + CoreImpl(Widen(ax), Widen(ay)) + ); + } + else + { + result = Narrow( + CoreImpl(WidenLower(ax), WidenLower(ay)), + CoreImpl(WidenUpper(ax), WidenUpper(ay)) + ); + } // IEEE 754 requires that we return +Infinity // if either input is Infinity, even if one of @@ -472,6 +761,12 @@ public static TVectorSingle HypotSingle(TVectorSin result = TVectorSingle.ConditionalSelect(infinityMask, TVectorSingle.Create(float.PositiveInfinity), result); return result; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static TVectorDouble CoreImpl(TVectorDouble x, TVectorDouble y) + { + return TVectorDouble.Sqrt(TVectorDouble.MultiplyAddEstimate(x, x, y * y)); + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1396,63 +1691,631 @@ public static TVectorSingle RoundSingle(TVectorSingle vector, Mid } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static TVectorDouble ConvertToDouble(TVectorInt64 vector) + public static (TVectorDouble Sin, TVectorDouble Cos) SinCosDouble(TVectorDouble x) where TVectorDouble : unmanaged, ISimdVector where TVectorInt64 : unmanaged, ISimdVector { - Unsafe.SkipInit(out TVectorDouble result); + // This code is based on `sin` and `cos` from amd/aocl-libm-ose + // Copyright (C) 2008-2022 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 - if (typeof(TVectorInt64) == typeof(Vector)) - { - result = (TVectorDouble)(object)Vector.ConvertToDouble((Vector)(object)vector); - } - else if (typeof(TVectorInt64) == typeof(Vector64)) - { - result = (TVectorDouble)(object)Vector64.ConvertToDouble((Vector64)(object)vector); - } - else if (typeof(TVectorInt64) == typeof(Vector128)) - { - result = (TVectorDouble)(object)Vector128.ConvertToDouble((Vector128)(object)vector); - } - else if (typeof(TVectorInt64) == typeof(Vector256)) + // See SinDouble and CosDouble for implementation details + + const long ARG_HUGE = 0x415312D000000000; // 5e6 + const long ARG_LARGE = 0x3FE921FB54442D18; // PI / 4 + const long ARG_SMALL = 0x3F20000000000000; // 2^-13 + const long ARG_SMALLER = 0x3E40000000000000; // 2^-27 + + TVectorDouble ax = TVectorDouble.Abs(x); + TVectorInt64 ux = Unsafe.BitCast(ax); + + TVectorDouble sinResult, cosResult; + + if (TVectorInt64.LessThanAll(ux, TVectorInt64.Create(ARG_LARGE + 1))) { - result = (TVectorDouble)(object)Vector256.ConvertToDouble((Vector256)(object)vector); + // We must be a finite value: (pi / 4) >= |x| + TVectorDouble x2 = x * x; + + if (TVectorInt64.GreaterThanAny(ux, TVectorInt64.Create(ARG_SMALL - 1))) + { + // at least one element is: |x| >= 2^-13 + sinResult = SinDoublePoly(x); + cosResult = TVectorDouble.MultiplyAddEstimate( + TVectorDouble.MultiplyAddEstimate( + CosDoublePoly(x), + x2, + TVectorDouble.Create(-0.5)), + x2, + TVectorDouble.One + ); + } + else + { + // at least one element is: 2^-13 > |x| + TVectorDouble x3 = x2 * x; + sinResult = TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(-0.16666666666666666), x3, x); + cosResult = TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(-0.5), x2, TVectorDouble.One); + } } - else if (typeof(TVectorInt64) == typeof(Vector512)) + else if (TVectorInt64.LessThanAll(ux, TVectorInt64.Create(ARG_HUGE))) { - result = (TVectorDouble)(object)Vector512.ConvertToDouble((Vector512)(object)vector); + // at least one element is: |x| > (pi / 4) -or- infinite -or- nan + (TVectorDouble r, TVectorDouble rr, TVectorInt64 region) = SinCosReduce(ax); + + TVectorDouble sin = SinDoubleLarge(r, rr); + TVectorDouble cos = CosDoubleLarge(r, rr); + + sinResult = TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.Equals(region & TVectorInt64.One, TVectorInt64.Zero)), + sin, // region 0 or 2 + cos // region 1 or 3 + ); + + cosResult = TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.Equals(region & TVectorInt64.One, TVectorInt64.Zero)), + cos, // region 0 or 2 + sin // region 1 or 3 + ); + + TVectorInt64 sign = Unsafe.BitCast(x) >>> 63; + + sinResult = TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.Equals(((sign & (region >>> 1)) | (~sign & ~(region >>> 1))) & TVectorInt64.One, TVectorInt64.Zero)), + -sinResult, // negative in region 1 or 3, positive in region 0 or 2 + +sinResult // negative in region 0 or 2, positive in region 1 or 3 + ); + + cosResult = TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.Equals((region + TVectorInt64.One) & TVectorInt64.Create(2), TVectorInt64.Zero)), + +cosResult, // region 0 or 3 + -cosResult // region 1 or 2 + ); } else { - ThrowHelper.ThrowNotSupportedException(); + return ScalarFallback(x); } - return result; + sinResult = TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.GreaterThan(ux, TVectorInt64.Create(ARG_SMALLER - 1))), + sinResult, // for elements: |x| >= 2^-27, infinity, or NaN + x // for elements: 2^-27 > |x| + ); + + cosResult = TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.GreaterThan(ux, TVectorInt64.Create(ARG_SMALLER - 1))), + cosResult, // for elements: |x| >= 2^-27, infinity, or NaN + TVectorDouble.One // for elements: 2^-27 > |x| + ); + + return (sinResult, cosResult); + + static (TVectorDouble Sin, TVectorDouble Cos) ScalarFallback(TVectorDouble x) + { + TVectorDouble sinResult = TVectorDouble.Zero; + TVectorDouble cosResult = TVectorDouble.Zero; + + for (int i = 0; i < TVectorDouble.Count; i++) + { + (double sinScalar, double cosScalar) = double.SinCos(x[i]); + sinResult = sinResult.WithElement(i, sinScalar); + cosResult = cosResult.WithElement(i, cosScalar); + } + + return (sinResult, cosResult); + } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static TVectorSingle ConvertToSingle(TVectorInt32 vector) + public static (TVectorSingle Sin, TVectorSingle Cos) SinCosSingle(TVectorSingle x) where TVectorSingle : unmanaged, ISimdVector where TVectorInt32 : unmanaged, ISimdVector + where TVectorDouble : unmanaged, ISimdVector + where TVectorInt64 : unmanaged, ISimdVector { - Unsafe.SkipInit(out TVectorSingle result); + // This code is based on `sinf` and `cosf` from amd/aocl-libm-ose + // Copyright (C) 2008-2022 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 - if (typeof(TVectorInt32) == typeof(Vector)) - { - result = (TVectorSingle)(object)Vector.ConvertToSingle((Vector)(object)vector); - } - else if (typeof(TVectorInt32) == typeof(Vector64)) + // See SinSingle and CosSingle for implementation details + + const int ARG_HUGE = 0x4A989680; // 5e6 + const int ARG_LARGE = 0x3F490FDB; // PI / 4 + const int ARG_SMALL = 0x3C000000; // 2^-13 + const int ARG_SMALLER = 0x39000000; // 2^-27 + + TVectorSingle ax = TVectorSingle.Abs(x); + TVectorInt32 ux = Unsafe.BitCast(ax); + + TVectorSingle sinResult, cosResult; + + if (TVectorInt32.LessThanAll(ux, TVectorInt32.Create(ARG_LARGE + 1))) { - result = (TVectorSingle)(object)Vector64.ConvertToSingle((Vector64)(object)vector); + // We must be a finite value: (pi / 4) >= |x| + + if (TVectorInt32.GreaterThanAny(ux, TVectorInt32.Create(ARG_SMALL - 1))) + { + // at least one element is: |x| >= 2^-13 + + if (TVectorSingle.Count == TVectorDouble.Count) + { + TVectorDouble dx = Widen(x); + + sinResult = Narrow( + SinSinglePoly(dx) + ); + cosResult = Narrow( + CosSingleSmall(dx) + ); + } + else + { + TVectorDouble dxLo = WidenLower(x); + TVectorDouble dxHi = WidenUpper(x); + + sinResult = Narrow( + SinSinglePoly(dxLo), + SinSinglePoly(dxHi) + ); + cosResult = Narrow( + CosSingleSmall(dxLo), + CosSingleSmall(dxHi) + ); + } + } + else + { + // at least one element is: 2^-13 > |x| + + TVectorSingle x2 = x * x; + TVectorSingle x3 = x2 * x; + + sinResult = TVectorSingle.MultiplyAddEstimate(TVectorSingle.Create(-0.16666667f), x3, x); + cosResult = TVectorSingle.MultiplyAddEstimate(TVectorSingle.Create(-0.5f), x2, TVectorSingle.One); + } } - else if (typeof(TVectorInt32) == typeof(Vector128)) + else if (TVectorInt32.LessThanAll(ux, TVectorInt32.Create(ARG_HUGE))) { - result = (TVectorSingle)(object)Vector128.ConvertToSingle((Vector128)(object)vector); + // at least one element is: |x| > (pi / 4) -or- infinite -or- nan + + if (TVectorSingle.Count == TVectorDouble.Count) + { + (TVectorDouble sin, TVectorDouble cos) = CoreImpl(Widen(x)); + + sinResult = Narrow(sin); + cosResult = Narrow(cos); + } + else + { + (TVectorDouble sinLo, TVectorDouble cosLo) = CoreImpl(WidenLower(x)); + (TVectorDouble sinHi, TVectorDouble cosHi) = CoreImpl(WidenUpper(x)); + + sinResult = Narrow(sinLo, sinHi); + cosResult = Narrow(cosLo, cosHi); + } } - else if (typeof(TVectorInt32) == typeof(Vector256)) + else { - result = (TVectorSingle)(object)Vector256.ConvertToSingle((Vector256)(object)vector); + return ScalarFallback(x); + } + + sinResult = TVectorSingle.ConditionalSelect( + Unsafe.BitCast(TVectorInt32.GreaterThan(ux, TVectorInt32.Create(ARG_SMALLER - 1))), + sinResult, // for elements: |x| >= 2^-27, infinity, or NaN + x // for elements: 2^-27 > |x| + ); + + cosResult = TVectorSingle.ConditionalSelect( + Unsafe.BitCast(TVectorInt32.GreaterThan(ux, TVectorInt32.Create(ARG_SMALLER - 1))), + cosResult, // for elements: |x| >= 2^-27, infinity, or NaN + TVectorSingle.One // for elements: 2^-27 > |x| + ); + + return (sinResult, cosResult); + + static (TVectorDouble Sin, TVectorDouble Cos) CoreImpl(TVectorDouble x) + { + TVectorDouble ax = TVectorDouble.Abs(x); + (TVectorDouble r, _, TVectorInt64 region) = SinCosReduce(ax); + + TVectorDouble sin = SinSinglePoly(r); + TVectorDouble cos = CosSingleLarge(r); + + TVectorDouble sinResult = TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.Equals(region & TVectorInt64.One, TVectorInt64.Zero)), + sin, // region 0 or 2 + cos // region 1 or 3 + ); + + TVectorDouble cosResult = TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.Equals(region & TVectorInt64.One, TVectorInt64.Zero)), + cos, // region 0 or 2 + sin // region 1 or 3 + ); + + TVectorInt64 sign = Unsafe.BitCast(x) >>> 63; + + sinResult = TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.Equals(((sign & (region >>> 1)) | (~sign & ~(region >>> 1))) & TVectorInt64.One, TVectorInt64.Zero)), + -sinResult, // negative in region 1 or 3, positive in region 0 or 2 + +sinResult // negative in region 0 or 2, positive in region 1 or 3 + ); + + cosResult = TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.Equals((region + TVectorInt64.One) & TVectorInt64.Create(2), TVectorInt64.Zero)), + +cosResult, // region 0 or 3 + -cosResult // region 1 or 2 + ); + + return (sinResult, cosResult); + } + + static (TVectorSingle Sin, TVectorSingle Cos) ScalarFallback(TVectorSingle x) + { + TVectorSingle sinResult = TVectorSingle.Zero; + TVectorSingle cosResult = TVectorSingle.Zero; + + for (int i = 0; i < TVectorSingle.Count; i++) + { + (float sinScalar, float cosScalar) = float.SinCos(x[i]); + sinResult = sinResult.WithElement(i, sinScalar); + cosResult = cosResult.WithElement(i, cosScalar); + } + + return (sinResult, cosResult); + } + } + + public static TVectorDouble SinDouble(TVectorDouble x) + where TVectorDouble : unmanaged, ISimdVector + where TVectorInt64 : unmanaged, ISimdVector + { + // This code is based on `sin` from amd/aocl-libm-ose + // Copyright (C) 2008-2022 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 + + // Implementation Notes + // --------------------- + // checks for special cases + // if ( ux = infinity) raise overflow exception and return x + // if x is NaN then raise invalid FP operation exception and return x. + // + // 1. Argument reduction + // if |x| > 5e5 then + // __amd_remainder_piby2(x, &r, &rr, ®ion) + // else + // Argument reduction + // Let z = |x| * 2/pi + // z = dn + r, where dn = round(z) + // rhead = dn * pi/2_head + // rtail = dn * pi/2_tail + // r = z – dn = |x| - rhead – rtail + // expdiff = exp(dn) – exp(r) + // if(expdiff) > 15) + // rtail = |x| - dn*pi/2_tail2 + // r = |x| - dn*pi/2_head - dn*pi/2_tail1 - dn*pi/2_tail2 - (((rhead + rtail) – rhead )-rtail) + // rr = (|x| – rhead) – r + rtail + // + // 2. Polynomial approximation + // if(dn is odd) + // rr = rr * r; + // x4 = x2 * x2; + // s = 0.5 * x2; + // t = s - 1.0; + // poly = x4 * (C1 + x2 * (C2 + x2 * (C3 + x2 * (C4 + x2 * (C5 + x2 * x6))))) + // r = (((1.0 + t) - s) - rr) + poly – t + // else + // x3 = x2 * r + // poly = S2 + (r2 * (S3 + (r2 * (S4 + (r2 * (S5 + S6 * r2)))))) + // r = r - ((x2 * (0.5*rr - x3 * poly)) - rr) - S1 * x3 + // if(((sign & region) | ((~sign) & (~region))) & 1) + // return r + // else + // return -r; + // + // if |x| < pi/4 && |x| > 2.0^(-13) + // sin(x) = x + (x * (r2 * (S1 + r2 * (S2 + r2 * (S3 + r2 * (S4 + r2 * (S5 + r2 * S6))))))) + // if |x| < 2.0^(-13) && |x| > 2.0^(-27) + // sin(x) = x - (x * x * x * (1/6)); + + const long ARG_HUGE = 0x415312D000000000; // 5e6 + const long ARG_LARGE = 0x3FE921FB54442D18; // PI / 4 + const long ARG_SMALL = 0x3F20000000000000; // 2^-13 + const long ARG_SMALLER = 0x3E40000000000000; // 2^-27 + + TVectorDouble ax = TVectorDouble.Abs(x); + TVectorInt64 ux = Unsafe.BitCast(ax); + + TVectorDouble result; + + if (TVectorInt64.LessThanAll(ux, TVectorInt64.Create(ARG_LARGE + 1))) + { + // We must be a finite value: (pi / 4) >= |x| + TVectorDouble x2 = x * x; + + if (TVectorInt64.GreaterThanAny(ux, TVectorInt64.Create(ARG_SMALL - 1))) + { + // at least one element is: |x| >= 2^-13 + result = SinDoublePoly(x); + } + else + { + // at least one element is: 2^-13 > |x| + TVectorDouble x3 = x2 * x; + result = TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(-0.16666666666666666), x3, x); + } + } + else if (TVectorInt64.LessThanAll(ux, TVectorInt64.Create(ARG_HUGE))) + { + // at least one element is: |x| > (pi / 4) -or- infinite -or- nan + (TVectorDouble r, TVectorDouble rr, TVectorInt64 region) = SinCosReduce(ax); + + TVectorDouble sin = SinDoubleLarge(r, rr); + TVectorDouble cos = CosDoubleLarge(r, rr); + + result = TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.Equals(region & TVectorInt64.One, TVectorInt64.Zero)), + sin, // region 0 or 2 + cos // region 1 or 3 + ); + + TVectorInt64 sign = Unsafe.BitCast(x) >>> 63; + + result = TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.Equals(((sign & (region >>> 1)) | (~sign & ~(region >>> 1))) & TVectorInt64.One, TVectorInt64.Zero)), + -result, // negative in region 1 or 3, positive in region 0 or 2 + +result // negative in region 0 or 2, positive in region 1 or 3 + ); + } + else + { + return ScalarFallback(x); + } + + return TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.GreaterThan(ux, TVectorInt64.Create(ARG_SMALLER - 1))), + result, // for elements: |x| >= 2^-27, infinity, or NaN + x // for elements: 2^-27 > |x| + ); + + static TVectorDouble ScalarFallback(TVectorDouble x) + { + TVectorDouble result = TVectorDouble.Zero; + + for (int i = 0; i < TVectorDouble.Count; i++) + { + double scalar = double.Sin(x[i]); + result = result.WithElement(i, scalar); + } + + return result; + } + } + + public static TVectorSingle SinSingle(TVectorSingle x) + where TVectorSingle : unmanaged, ISimdVector + where TVectorInt32 : unmanaged, ISimdVector + where TVectorDouble : unmanaged, ISimdVector + where TVectorInt64 : unmanaged, ISimdVector + { + // This code is based on `sinf` from amd/aocl-libm-ose + // Copyright (C) 2008-2022 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 + + // Implementation Notes + // --------------------- + // checks for special cases + // if ( ux = infinity) raise overflow exception and return x + // if x is NaN then raise invalid FP operation exception and return x. + // + // 1. Argument reduction + // if |x| > 5e5 then + // __amd_remainder_piby2(x, &r, &rr, ®ion) + // else + // Argument reduction + // Let z = |x| * 2/pi + // z = dn + r, where dn = round(z) + // rhead = dn * pi/2_head + // rtail = dn * pi/2_tail + // r = z – dn = |x| - rhead – rtail + // expdiff = exp(dn) – exp(r) + // if(expdiff) > 15) + // rtail = |x| - dn*pi/2_tail2 + // r = |x| - dn*pi/2_head - dn*pi/2_tail1 - dn*pi/2_tail2 - (((rhead + rtail) – rhead )-rtail) + // rr = (|x| – rhead) – r + rtail + // + // 2. Polynomial approximation + // if(dn is odd) + // rr = rr * r; + // x4 = x2 * x2; + // s = 0.5 * x2; + // t = s - 1.0; + // poly = x4 * (C1 + x2 * (C2 + x2 * (C3 + x2 * (C4)))) + // r = (((1.0 + t) - s) - rr) + poly – t + // else + // x3 = x2 * r + // poly = S2 + (r2 * (S3 + (r2 * (S4)))) + // r = r - ((x2 * (0.5*rr - x3 * poly)) - rr) - S1 * x3 + // if(((sign & region) | ((~sign) & (~region))) & 1) + // return r + // else + // return -r; + // + // if |x| < pi/4 && |x| > 2.0^(-13) + // sin(x) = x + (x * (r2 * (S1 + r2 * (S2 + r2 * (S3 + r2 * (S4))))) + // if |x| < 2.0^(-13) && |x| > 2.0^(-27) + // sin(x) = x - (x * x * x * (1/6)); + + const int ARG_HUGE = 0x4A989680; // 5e6 + const int ARG_LARGE = 0x3F490FDB; // PI / 4 + const int ARG_SMALL = 0x3C000000; // 2^-13 + const int ARG_SMALLER = 0x39000000; // 2^-27 + + TVectorSingle ax = TVectorSingle.Abs(x); + TVectorInt32 ux = Unsafe.BitCast(ax); + + TVectorSingle result; + + if (TVectorInt32.LessThanAll(ux, TVectorInt32.Create(ARG_LARGE + 1))) + { + // We must be a finite value: (pi / 4) >= |x| + + if (TVectorInt32.GreaterThanAny(ux, TVectorInt32.Create(ARG_SMALL - 1))) + { + // at least one element is: |x| >= 2^-13 + + if (TVectorSingle.Count == TVectorDouble.Count) + { + result = Narrow( + SinSinglePoly(Widen(x)) + ); + } + else + { + result = Narrow( + SinSinglePoly(WidenLower(x)), + SinSinglePoly(WidenUpper(x)) + ); + } + } + else + { + // at least one element is: 2^-13 > |x| + TVectorSingle x3 = (x * x) * x; + result = TVectorSingle.MultiplyAddEstimate(TVectorSingle.Create(-0.16666667f), x3, x); + } + } + else if (TVectorInt32.LessThanAll(ux, TVectorInt32.Create(ARG_HUGE))) + { + // at least one element is: |x| > (pi / 4) -or- infinite -or- nan + + if (TVectorSingle.Count == TVectorDouble.Count) + { + result = Narrow( + CoreImpl(Widen(x)) + ); + } + else + { + result = Narrow( + CoreImpl(WidenLower(x)), + CoreImpl(WidenUpper(x)) + ); + } + } + else + { + return ScalarFallback(x); + } + + return TVectorSingle.ConditionalSelect( + Unsafe.BitCast(TVectorInt32.GreaterThan(ux, TVectorInt32.Create(ARG_SMALLER - 1))), + result, // for elements: |x| >= 2^-27, infinity, or NaN + x // for elements: 2^-27 > |x| + ); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static TVectorDouble CoreImpl(TVectorDouble x) + { + TVectorDouble ax = TVectorDouble.Abs(x); + (TVectorDouble r, _, TVectorInt64 region) = SinCosReduce(ax); + + TVectorDouble sin = SinSinglePoly(r); + TVectorDouble cos = CosSingleLarge(r); + + TVectorDouble result = TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.Equals(region & TVectorInt64.One, TVectorInt64.Zero)), + sin, // region 0 or 2 + cos // region 1 or 3 + ); + + TVectorInt64 sign = Unsafe.BitCast(x) >>> 63; + + return TVectorDouble.ConditionalSelect( + Unsafe.BitCast(TVectorInt64.Equals(((sign & (region >>> 1)) | (~sign & ~(region >>> 1))) & TVectorInt64.One, TVectorInt64.Zero)), + -result, // negative in region 1 or 3, positive in region 0 or 2 + +result // negative in region 0 or 2, positive in region 1 or 3 + ); + } + + static TVectorSingle ScalarFallback(TVectorSingle x) + { + TVectorSingle result = TVectorSingle.Zero; + + for (int i = 0; i < TVectorSingle.Count; i++) + { + float scalar = float.Sin(x[i]); + result = result.WithElement(i, scalar); + } + + return result; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TVectorDouble ConvertToDouble(TVectorInt64 vector) + where TVectorDouble : unmanaged, ISimdVector + where TVectorInt64 : unmanaged, ISimdVector + { + Unsafe.SkipInit(out TVectorDouble result); + + if (typeof(TVectorInt64) == typeof(Vector)) + { + result = (TVectorDouble)(object)Vector.ConvertToDouble((Vector)(object)vector); + } + else if (typeof(TVectorInt64) == typeof(Vector64)) + { + result = (TVectorDouble)(object)Vector64.ConvertToDouble((Vector64)(object)vector); + } + else if (typeof(TVectorInt64) == typeof(Vector128)) + { + result = (TVectorDouble)(object)Vector128.ConvertToDouble((Vector128)(object)vector); + } + else if (typeof(TVectorInt64) == typeof(Vector256)) + { + result = (TVectorDouble)(object)Vector256.ConvertToDouble((Vector256)(object)vector); + } + else if (typeof(TVectorInt64) == typeof(Vector512)) + { + result = (TVectorDouble)(object)Vector512.ConvertToDouble((Vector512)(object)vector); + } + else + { + ThrowHelper.ThrowNotSupportedException(); + } + + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TVectorSingle ConvertToSingle(TVectorInt32 vector) + where TVectorSingle : unmanaged, ISimdVector + where TVectorInt32 : unmanaged, ISimdVector + { + Unsafe.SkipInit(out TVectorSingle result); + + if (typeof(TVectorInt32) == typeof(Vector)) + { + result = (TVectorSingle)(object)Vector.ConvertToSingle((Vector)(object)vector); + } + else if (typeof(TVectorInt32) == typeof(Vector64)) + { + result = (TVectorSingle)(object)Vector64.ConvertToSingle((Vector64)(object)vector); + } + else if (typeof(TVectorInt32) == typeof(Vector128)) + { + result = (TVectorSingle)(object)Vector128.ConvertToSingle((Vector128)(object)vector); + } + else if (typeof(TVectorInt32) == typeof(Vector256)) + { + result = (TVectorSingle)(object)Vector256.ConvertToSingle((Vector256)(object)vector); } else if (typeof(TVectorInt32) == typeof(Vector512)) { @@ -1466,6 +2329,96 @@ private static TVectorSingle ConvertToSingle(TVecto return result; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TVectorDouble CosDoubleLarge(TVectorDouble r, TVectorDouble rr) + where TVectorDouble : unmanaged, ISimdVector + { + TVectorDouble r2 = r * r; + TVectorDouble r4 = r2 * r2; + + TVectorDouble s = r2 * 0.5; + TVectorDouble t = s - TVectorDouble.One; + + return TVectorDouble.MultiplyAddEstimate( + CosDoublePoly(r), + r4, + TVectorDouble.MultiplyAddEstimate(r, rr, ((TVectorDouble.One + t) - s)) + ) - t; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TVectorDouble CosDoublePoly(TVectorDouble r) + where TVectorDouble : unmanaged, ISimdVector + { + const double C1 = +0.041666666666666664; + const double C2 = -0.0013888888888887398; + const double C3 = +2.4801587298767044E-05; + const double C4 = -2.755731727234489E-07; + const double C5 = +2.0876146382372144E-09; + const double C6 = -1.138263981623609E-11; + + TVectorDouble r2 = r * r; + TVectorDouble r4 = r2 * r2; + TVectorDouble r8 = r4 * r4; + + return TVectorDouble.MultiplyAddEstimate( + TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(C6), r2, TVectorDouble.Create(C5)), + r8, + TVectorDouble.MultiplyAddEstimate( + TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(C4), r2, TVectorDouble.Create(C3)), + r4, + TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(C2), r2, TVectorDouble.Create(C1)) + ) + ); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TVectorDouble CosSingleLarge(TVectorDouble r) + where TVectorDouble : unmanaged, ISimdVector + { + TVectorDouble r2 = r * r; + TVectorDouble r4 = r2 * r2; + + return TVectorDouble.MultiplyAddEstimate( + CosSinglePoly(r), + r4, + TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(-0.5), r2, TVectorDouble.One) + ); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TVectorDouble CosSinglePoly(TVectorDouble r) + where TVectorDouble : unmanaged, ISimdVector + { + const double C1 = +0.041666666666666664; + const double C2 = -0.0013888888888887398; + const double C3 = +2.4801587298767044E-05; + const double C4 = -2.755731727234489E-07; + + TVectorDouble r2 = r * r; + TVectorDouble r4 = r2 * r2; + + return TVectorDouble.MultiplyAddEstimate( + TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(C4), r2, TVectorDouble.Create(C3)), + r4, + TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(C2), r2, TVectorDouble.Create(C1)) + ); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TVectorDouble CosSingleSmall(TVectorDouble x) + where TVectorDouble : unmanaged, ISimdVector + { + TVectorDouble x2 = x * x; + TVectorDouble x4 = x2 * x2; + + TVectorDouble r = x2 * 0.5; + TVectorDouble t = TVectorDouble.One - r; + TVectorDouble s = t + (TVectorDouble.One - t - r); + + return TVectorDouble.MultiplyAddEstimate(CosSinglePoly(x), x4, s); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static TVector Create(double value) where TVector : unmanaged, ISimdVector @@ -1534,6 +2487,63 @@ private static TVector Create(float value) return result; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TVectorSingle Narrow(TVectorDouble vector) + where TVectorDouble : unmanaged, ISimdVector + where TVectorSingle : unmanaged, ISimdVector + { + Unsafe.SkipInit(out TVectorSingle result); + + if (typeof(TVectorDouble) == typeof(Vector128)) + { + Debug.Assert(typeof(TVectorSingle) == typeof(Vector64)); + + if (AdvSimd.Arm64.IsSupported) + { + result = (TVectorSingle)(object)AdvSimd.Arm64.ConvertToSingleLower((Vector128)(object)vector); + } + else + { + Vector128 value = (Vector128)(object)vector; + result = (TVectorSingle)(object)Vector64.Narrow(value.GetLower(), value.GetUpper()); + } + } + else if (typeof(TVectorDouble) == typeof(Vector256)) + { + Debug.Assert(typeof(TVectorSingle) == typeof(Vector128)); + + if (Avx.IsSupported) + { + result = (TVectorSingle)(object)Avx.ConvertToVector128Single((Vector256)(object)vector); + } + else + { + Vector256 value = (Vector256)(object)vector; + result = (TVectorSingle)(object)Vector128.Narrow(value.GetLower(), value.GetUpper()); + } + } + else if (typeof(TVectorDouble) == typeof(Vector512)) + { + Debug.Assert(typeof(TVectorSingle) == typeof(Vector256)); + + if (Avx512F.IsSupported) + { + result = (TVectorSingle)(object)Avx512F.ConvertToVector256Single((Vector512)(object)vector); + } + else + { + Vector512 value = (Vector512)(object)vector; + result = (TVectorSingle)(object)Vector256.Narrow(value.GetLower(), value.GetUpper()); + } + } + else + { + ThrowHelper.ThrowNotSupportedException(); + } + + return result; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static TVectorSingle Narrow(TVectorDouble lower, TVectorDouble upper) where TVectorDouble : unmanaged, ISimdVector @@ -1575,36 +2585,263 @@ private static TVectorSingle Narrow(TVectorDouble } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static (TVectorDouble Lower, TVectorDouble Upper) Widen(TVectorSingle vector) + private static TVectorDouble SinDoubleLarge(TVectorDouble r, TVectorDouble rr) + where TVectorDouble : unmanaged, ISimdVector + { + const double S1 = -0.16666666666666666; + const double S2 = +0.00833333333333095; + const double S3 = -0.00019841269836761127; + const double S4 = +2.7557316103728802E-06; + const double S5 = -2.5051132068021698E-08; + const double S6 = +1.5918144304485914E-10; + + TVectorDouble r2 = r * r; + TVectorDouble r3 = r2 * r; + TVectorDouble r4 = r2 * r2; + TVectorDouble r8 = r4 * r4; + + TVectorDouble sinPoly = TVectorDouble.MultiplyAddEstimate( + TVectorDouble.Create(S6), + r8, + TVectorDouble.MultiplyAddEstimate( + TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(S5), r2, TVectorDouble.Create(S4)), + r4, + TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(S3), r2, TVectorDouble.Create(S2)) + ) + ); + + return r - TVectorDouble.MultiplyAddEstimate( + TVectorDouble.Create(-S1), + r3, + TVectorDouble.MultiplyAddEstimate( + TVectorDouble.MultiplyAddEstimate(rr, TVectorDouble.Create(0.5), -(r3 * sinPoly)), + r2, + -rr + ) + ); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TVectorDouble SinDoublePoly(TVectorDouble r) + where TVectorDouble : unmanaged, ISimdVector + { + const double S1 = -0.16666666666666666; + const double S2 = +0.00833333333333095; + const double S3 = -0.00019841269836761127; + const double S4 = +2.7557316103728802E-06; + const double S5 = -2.5051132068021698E-08; + const double S6 = +1.5918144304485914E-10; + + TVectorDouble r2 = r * r; + TVectorDouble r3 = r2 * r; + TVectorDouble r4 = r2 * r2; + TVectorDouble r8 = r4 * r4; + + TVectorDouble poly = TVectorDouble.MultiplyAddEstimate( + TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(S6), r2, TVectorDouble.Create(S5)), + r8, + TVectorDouble.MultiplyAddEstimate( + TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(S4), r2, TVectorDouble.Create(S3)), + r4, + TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(S2), r2, TVectorDouble.Create(S1))) + ); + + return TVectorDouble.MultiplyAddEstimate(poly, r3, r); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TVectorDouble SinSinglePoly(TVectorDouble r) + where TVectorDouble : unmanaged, ISimdVector + { + const double S1 = -0.16666666666666666; + const double S2 = +0.00833333333333095; + const double S3 = -0.00019841269836761127; + const double S4 = +2.7557316103728802E-06; + + TVectorDouble r2 = r * r; + TVectorDouble r3 = r2 * r; + TVectorDouble r4 = r2 * r2; + + return TVectorDouble.MultiplyAddEstimate( + TVectorDouble.MultiplyAddEstimate( + TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(S4), r2, TVectorDouble.Create(S3)), + r4, + TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(S2), r2, TVectorDouble.Create(S1))), + r3, + r + ); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static (TVectorDouble r, TVectorDouble rr, TVectorInt64 region) SinCosReduce(TVectorDouble ax) + where TVectorDouble : unmanaged, ISimdVector + where TVectorInt64 : unmanaged, ISimdVector + { + // reduce the argument to be in a range from (-pi / 4) to (+pi / 4) by subtracting multiples of (pi / 2) + + const double V_ALM_SHIFT = 6755399441055744.0; + const double V_TWO_BY_PI = 0.6366197723675814; + + const double V_PI_BY_TWO_1 = 1.5707963267341256; + const double V_PI_BY_TWO_2 = 6.077100506303966E-11; + const double V_PI_BY_TWO_2_TAIL = 2.0222662487959506E-21; + + // dn = (int)(|x| * 2 / pi) + TVectorDouble npi2 = TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(V_TWO_BY_PI), ax, TVectorDouble.Create(V_ALM_SHIFT)); + TVectorInt64 region = Unsafe.BitCast(npi2); + npi2 -= TVectorDouble.Create(V_ALM_SHIFT); + + TVectorDouble rhead = TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(-V_PI_BY_TWO_1), npi2, ax); + TVectorDouble rtail = npi2 * V_PI_BY_TWO_2; + TVectorDouble r = rhead - rtail; + + rtail = TVectorDouble.MultiplyAddEstimate(TVectorDouble.Create(V_PI_BY_TWO_2_TAIL), npi2, -(rhead - r - rtail)); + rhead = r; + r -= rtail; + + return (r, (rhead - r) - rtail, region); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TVectorDouble Widen(TVectorSingle vector) + where TVectorSingle : unmanaged, ISimdVector + where TVectorDouble : unmanaged, ISimdVector + { + Unsafe.SkipInit(out TVectorDouble result); + + if (typeof(TVectorSingle) == typeof(Vector64)) + { + Debug.Assert(typeof(TVectorDouble) == typeof(Vector128)); + + if (AdvSimd.Arm64.IsSupported) + { + result = (TVectorDouble)(object)AdvSimd.Arm64.ConvertToDouble((Vector64)(object)vector); + } + else + { + Vector64 value = (Vector64)(object)vector; + + Vector64 lower = Vector64.WidenLower(value); + Vector64 upper = Vector64.WidenUpper(value); + + result = (TVectorDouble)(object)Vector128.Create(lower, upper); + } + } + else if (typeof(TVectorSingle) == typeof(Vector128)) + { + Debug.Assert(typeof(TVectorDouble) == typeof(Vector256)); + + if (Avx.IsSupported) + { + result = (TVectorDouble)(object)Avx.ConvertToVector256Double((Vector128)(object)vector); + } + else + { + Vector128 value = (Vector128)(object)vector; + + Vector128 lower = Vector128.WidenLower(value); + Vector128 upper = Vector128.WidenUpper(value); + + result = (TVectorDouble)(object)Vector256.Create(lower, upper); + } + } + else if (typeof(TVectorSingle) == typeof(Vector256)) + { + Debug.Assert(typeof(TVectorDouble) == typeof(Vector512)); + + if (Avx512F.IsSupported) + { + result = (TVectorDouble)(object)Avx512F.ConvertToVector512Double((Vector256)(object)vector); + } + else + { + Vector256 value = (Vector256)(object)vector; + + Vector256 lower = Vector256.WidenLower(value); + Vector256 upper = Vector256.WidenUpper(value); + + result = (TVectorDouble)(object)Vector512.Create(lower, upper); + } + } + else + { + ThrowHelper.ThrowNotSupportedException(); + } + + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TVectorDouble WidenLower(TVectorSingle vector) + where TVectorSingle : unmanaged, ISimdVector + where TVectorDouble : unmanaged, ISimdVector + { + Unsafe.SkipInit(out TVectorDouble result); + + if (typeof(TVectorSingle) == typeof(Vector)) + { + Debug.Assert(typeof(TVectorDouble) == typeof(Vector)); + result = (TVectorDouble)(object)Vector.WidenLower((Vector)(object)vector); + } + else if (typeof(TVectorSingle) == typeof(Vector64)) + { + Debug.Assert(typeof(TVectorDouble) == typeof(Vector64)); + result = (TVectorDouble)(object)Vector64.WidenLower((Vector64)(object)vector); + } + else if (typeof(TVectorSingle) == typeof(Vector128)) + { + Debug.Assert(typeof(TVectorDouble) == typeof(Vector128)); + result = (TVectorDouble)(object)Vector128.WidenLower((Vector128)(object)vector); + } + else if (typeof(TVectorSingle) == typeof(Vector256)) + { + Debug.Assert(typeof(TVectorDouble) == typeof(Vector256)); + result = (TVectorDouble)(object)Vector256.WidenLower((Vector256)(object)vector); + } + else if (typeof(TVectorSingle) == typeof(Vector512)) + { + Debug.Assert(typeof(TVectorDouble) == typeof(Vector512)); + result = (TVectorDouble)(object)Vector512.WidenLower((Vector512)(object)vector); + } + else + { + ThrowHelper.ThrowNotSupportedException(); + } + + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TVectorDouble WidenUpper(TVectorSingle vector) where TVectorSingle : unmanaged, ISimdVector where TVectorDouble : unmanaged, ISimdVector { - Unsafe.SkipInit(out (TVectorDouble, TVectorDouble) result); + Unsafe.SkipInit(out TVectorDouble result); if (typeof(TVectorSingle) == typeof(Vector)) { Debug.Assert(typeof(TVectorDouble) == typeof(Vector)); - result = ((TVectorDouble, TVectorDouble))(object)Vector.Widen((Vector)(object)vector); + result = (TVectorDouble)(object)Vector.WidenUpper((Vector)(object)vector); } else if (typeof(TVectorSingle) == typeof(Vector64)) { Debug.Assert(typeof(TVectorDouble) == typeof(Vector64)); - result = ((TVectorDouble, TVectorDouble))(object)Vector64.Widen((Vector64)(object)vector); + result = (TVectorDouble)(object)Vector64.WidenUpper((Vector64)(object)vector); } else if (typeof(TVectorSingle) == typeof(Vector128)) { Debug.Assert(typeof(TVectorDouble) == typeof(Vector128)); - result = ((TVectorDouble, TVectorDouble))(object)Vector128.Widen((Vector128)(object)vector); + result = (TVectorDouble)(object)Vector128.WidenUpper((Vector128)(object)vector); } else if (typeof(TVectorSingle) == typeof(Vector256)) { Debug.Assert(typeof(TVectorDouble) == typeof(Vector256)); - result = ((TVectorDouble, TVectorDouble))(object)Vector256.Widen((Vector256)(object)vector); + result = (TVectorDouble)(object)Vector256.WidenUpper((Vector256)(object)vector); } else if (typeof(TVectorSingle) == typeof(Vector512)) { Debug.Assert(typeof(TVectorDouble) == typeof(Vector512)); - result = ((TVectorDouble, TVectorDouble))(object)Vector512.Widen((Vector512)(object)vector); + result = (TVectorDouble)(object)Vector512.WidenUpper((Vector512)(object)vector); } else { diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index 7d4b69672a7f98..2dc63bb054ea81 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -71,6 +71,8 @@ public static partial class Vector128 public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, System.Span destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, T[] destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, T[] destination, int startIndex) { } + public static System.Runtime.Intrinsics.Vector128 Cos(System.Runtime.Intrinsics.Vector128 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector128 Cos(System.Runtime.Intrinsics.Vector128 vector) { throw null; } public static System.Runtime.Intrinsics.Vector128 Create(byte value) { throw null; } public static System.Runtime.Intrinsics.Vector128 Create(byte e0, byte e1, byte e2, byte e3, byte e4, byte e5, byte e6, byte e7, byte e8, byte e9, byte e10, byte e11, byte e12, byte e13, byte e14, byte e15) { throw null; } public static System.Runtime.Intrinsics.Vector128 Create(double value) { throw null; } @@ -299,6 +301,10 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector128 Shuffle(System.Runtime.Intrinsics.Vector128 vector, System.Runtime.Intrinsics.Vector128 indices) { throw null; } public static System.Runtime.Intrinsics.Vector128 Shuffle(System.Runtime.Intrinsics.Vector128 vector, System.Runtime.Intrinsics.Vector128 indices) { throw null; } + public static System.Runtime.Intrinsics.Vector128 Sin(System.Runtime.Intrinsics.Vector128 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector128 Sin(System.Runtime.Intrinsics.Vector128 vector) { throw null; } + public static (System.Runtime.Intrinsics.Vector128 Sin, System.Runtime.Intrinsics.Vector128 Cos) SinCos(System.Runtime.Intrinsics.Vector128 vector) { throw null; } + public static (System.Runtime.Intrinsics.Vector128 Sin, System.Runtime.Intrinsics.Vector128 Cos) SinCos(System.Runtime.Intrinsics.Vector128 vector) { throw null; } public static System.Runtime.Intrinsics.Vector128 Sqrt(System.Runtime.Intrinsics.Vector128 vector) { throw null; } [System.CLSCompliantAttribute(false)] public static unsafe void Store(this System.Runtime.Intrinsics.Vector128 source, T* destination) { throw null; } @@ -443,6 +449,8 @@ public static partial class Vector256 public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, System.Span destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, T[] destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, T[] destination, int startIndex) { } + public static System.Runtime.Intrinsics.Vector256 Cos(System.Runtime.Intrinsics.Vector256 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector256 Cos(System.Runtime.Intrinsics.Vector256 vector) { throw null; } public static System.Runtime.Intrinsics.Vector256 Create(byte value) { throw null; } public static System.Runtime.Intrinsics.Vector256 Create(byte e0, byte e1, byte e2, byte e3, byte e4, byte e5, byte e6, byte e7, byte e8, byte e9, byte e10, byte e11, byte e12, byte e13, byte e14, byte e15, byte e16, byte e17, byte e18, byte e19, byte e20, byte e21, byte e22, byte e23, byte e24, byte e25, byte e26, byte e27, byte e28, byte e29, byte e30, byte e31) { throw null; } public static System.Runtime.Intrinsics.Vector256 Create(double value) { throw null; } @@ -672,6 +680,10 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector256 Shuffle(System.Runtime.Intrinsics.Vector256 vector, System.Runtime.Intrinsics.Vector256 indices) { throw null; } public static System.Runtime.Intrinsics.Vector256 Shuffle(System.Runtime.Intrinsics.Vector256 vector, System.Runtime.Intrinsics.Vector256 indices) { throw null; } + public static System.Runtime.Intrinsics.Vector256 Sin(System.Runtime.Intrinsics.Vector256 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector256 Sin(System.Runtime.Intrinsics.Vector256 vector) { throw null; } + public static (System.Runtime.Intrinsics.Vector256 Sin, System.Runtime.Intrinsics.Vector256 Cos) SinCos(System.Runtime.Intrinsics.Vector256 vector) { throw null; } + public static (System.Runtime.Intrinsics.Vector256 Sin, System.Runtime.Intrinsics.Vector256 Cos) SinCos(System.Runtime.Intrinsics.Vector256 vector) { throw null; } public static System.Runtime.Intrinsics.Vector256 Sqrt(System.Runtime.Intrinsics.Vector256 vector) { throw null; } [System.CLSCompliantAttribute(false)] public static unsafe void Store(this System.Runtime.Intrinsics.Vector256 source, T* destination) { throw null; } @@ -816,6 +828,8 @@ public static partial class Vector512 public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, System.Span destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, T[] destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, T[] destination, int startIndex) { } + public static System.Runtime.Intrinsics.Vector512 Cos(System.Runtime.Intrinsics.Vector512 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector512 Cos(System.Runtime.Intrinsics.Vector512 vector) { throw null; } public static System.Runtime.Intrinsics.Vector512 Create(byte value) { throw null; } public static System.Runtime.Intrinsics.Vector512 Create(byte e0, byte e1, byte e2, byte e3, byte e4, byte e5, byte e6, byte e7, byte e8, byte e9, byte e10, byte e11, byte e12, byte e13, byte e14, byte e15, byte e16, byte e17, byte e18, byte e19, byte e20, byte e21, byte e22, byte e23, byte e24, byte e25, byte e26, byte e27, byte e28, byte e29, byte e30, byte e31, byte e32, byte e33, byte e34, byte e35, byte e36, byte e37, byte e38, byte e39, byte e40, byte e41, byte e42, byte e43, byte e44, byte e45, byte e46, byte e47, byte e48, byte e49, byte e50, byte e51, byte e52, byte e53, byte e54, byte e55, byte e56, byte e57, byte e58, byte e59, byte e60, byte e61, byte e62, byte e63) { throw null; } public static System.Runtime.Intrinsics.Vector512 Create(double value) { throw null; } @@ -1046,6 +1060,10 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector512 Shuffle(System.Runtime.Intrinsics.Vector512 vector, System.Runtime.Intrinsics.Vector512 indices) { throw null; } public static System.Runtime.Intrinsics.Vector512 Shuffle(System.Runtime.Intrinsics.Vector512 vector, System.Runtime.Intrinsics.Vector512 indices) { throw null; } + public static System.Runtime.Intrinsics.Vector512 Sin(System.Runtime.Intrinsics.Vector512 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector512 Sin(System.Runtime.Intrinsics.Vector512 vector) { throw null; } + public static (System.Runtime.Intrinsics.Vector512 Sin, System.Runtime.Intrinsics.Vector512 Cos) SinCos(System.Runtime.Intrinsics.Vector512 vector) { throw null; } + public static (System.Runtime.Intrinsics.Vector512 Sin, System.Runtime.Intrinsics.Vector512 Cos) SinCos(System.Runtime.Intrinsics.Vector512 vector) { throw null; } public static System.Runtime.Intrinsics.Vector512 Sqrt(System.Runtime.Intrinsics.Vector512 vector) { throw null; } [System.CLSCompliantAttribute(false)] public static unsafe void Store(this System.Runtime.Intrinsics.Vector512 source, T* destination) { throw null; } @@ -1186,6 +1204,8 @@ public static partial class Vector64 public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, System.Span destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, T[] destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, T[] destination, int startIndex) { } + public static System.Runtime.Intrinsics.Vector64 Cos(System.Runtime.Intrinsics.Vector64 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector64 Cos(System.Runtime.Intrinsics.Vector64 vector) { throw null; } public static System.Runtime.Intrinsics.Vector64 Create(byte value) { throw null; } public static System.Runtime.Intrinsics.Vector64 Create(byte e0, byte e1, byte e2, byte e3, byte e4, byte e5, byte e6, byte e7) { throw null; } public static System.Runtime.Intrinsics.Vector64 Create(double value) { throw null; } @@ -1385,6 +1405,10 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector64 Shuffle(System.Runtime.Intrinsics.Vector64 vector, System.Runtime.Intrinsics.Vector64 indices) { throw null; } public static System.Runtime.Intrinsics.Vector64 Shuffle(System.Runtime.Intrinsics.Vector64 vector, System.Runtime.Intrinsics.Vector64 indices) { throw null; } + public static System.Runtime.Intrinsics.Vector64 Sin(System.Runtime.Intrinsics.Vector64 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector64 Sin(System.Runtime.Intrinsics.Vector64 vector) { throw null; } + public static (System.Runtime.Intrinsics.Vector64 Sin, System.Runtime.Intrinsics.Vector64 Cos) SinCos(System.Runtime.Intrinsics.Vector64 vector) { throw null; } + public static (System.Runtime.Intrinsics.Vector64 Sin, System.Runtime.Intrinsics.Vector64 Cos) SinCos(System.Runtime.Intrinsics.Vector64 vector) { throw null; } public static System.Runtime.Intrinsics.Vector64 Sqrt(System.Runtime.Intrinsics.Vector64 vector) { throw null; } [System.CLSCompliantAttribute(false)] public static unsafe void Store(this System.Runtime.Intrinsics.Vector64 source, T* destination) { throw null; } diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs index 5c32e8b991e7e0..27955248daac8c 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs @@ -4824,6 +4824,22 @@ private static void TestCreateSequence(T start, T step) } } + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CosDouble), MemberType = typeof(GenericMathTestMemberData))] + public void CosDoubleTest(double value, double expectedResult, double variance) + { + Vector128 actualResult = Vector128.Cos(Vector128.Create(value)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CosSingle), MemberType = typeof(GenericMathTestMemberData))] + public void CosSingleTest(float value, float expectedResult, float variance) + { + Vector128 actualResult = Vector128.Cos(Vector128.Create(value)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Create(variance)); + } + [Theory] [MemberData(nameof(GenericMathTestMemberData.ExpDouble), MemberType = typeof(GenericMathTestMemberData))] public void ExpDoubleTest(double value, double expectedResult, double variance) @@ -5329,6 +5345,40 @@ public void RoundToEvenSingleTest(float value, float expectedResult) AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); } + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinDouble), MemberType = typeof(GenericMathTestMemberData))] + public void SinDoubleTest(double value, double expectedResult, double variance) + { + Vector128 actualResult = Vector128.Sin(Vector128.Create(value)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinSingle), MemberType = typeof(GenericMathTestMemberData))] + public void SinSingleTest(float value, float expectedResult, float variance) + { + Vector128 actualResult = Vector128.Sin(Vector128.Create(value)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinCosDouble), MemberType = typeof(GenericMathTestMemberData))] + public void SinCosDoubleTest(double value, double expectedResultSin, double expectedResultCos, double allowedVarianceSin, double allowedVarianceCos) + { + (Vector128 resultSin, Vector128 resultCos) = Vector128.SinCos(Vector128.Create(value)); + AssertEqual(Vector128.Create(expectedResultSin), resultSin, Vector128.Create(allowedVarianceSin)); + AssertEqual(Vector128.Create(expectedResultCos), resultCos, Vector128.Create(allowedVarianceCos)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinCosSingle), MemberType = typeof(GenericMathTestMemberData))] + public void SinCosSingleTest(float value, float expectedResultSin, float expectedResultCos, float allowedVarianceSin, float allowedVarianceCos) + { + (Vector128 resultSin, Vector128 resultCos) = Vector128.SinCos(Vector128.Create(value)); + AssertEqual(Vector128.Create(expectedResultSin), resultSin, Vector128.Create(allowedVarianceSin)); + AssertEqual(Vector128.Create(expectedResultCos), resultCos, Vector128.Create(allowedVarianceCos)); + } + [Theory] [MemberData(nameof(GenericMathTestMemberData.TruncateDouble), MemberType = typeof(GenericMathTestMemberData))] public void TruncateDoubleTest(double value, double expectedResult) diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs index 0c5cd3bdb2e828..d16e5eed481809 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs @@ -5840,6 +5840,22 @@ private static void TestCreateSequence(T start, T step) } } + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CosDouble), MemberType = typeof(GenericMathTestMemberData))] + public void CosDoubleTest(double value, double expectedResult, double variance) + { + Vector256 actualResult = Vector256.Cos(Vector256.Create(value)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CosSingle), MemberType = typeof(GenericMathTestMemberData))] + public void CosSingleTest(float value, float expectedResult, float variance) + { + Vector256 actualResult = Vector256.Cos(Vector256.Create(value)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Create(variance)); + } + [Theory] [MemberData(nameof(GenericMathTestMemberData.ExpDouble), MemberType = typeof(GenericMathTestMemberData))] public void ExpDoubleTest(double value, double expectedResult, double variance) @@ -6345,6 +6361,40 @@ public void RoundToEvenSingleTest(float value, float expectedResult) AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); } + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinDouble), MemberType = typeof(GenericMathTestMemberData))] + public void SinDoubleTest(double value, double expectedResult, double variance) + { + Vector256 actualResult = Vector256.Sin(Vector256.Create(value)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinSingle), MemberType = typeof(GenericMathTestMemberData))] + public void SinSingleTest(float value, float expectedResult, float variance) + { + Vector256 actualResult = Vector256.Sin(Vector256.Create(value)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinCosDouble), MemberType = typeof(GenericMathTestMemberData))] + public void SinCosDoubleTest(double value, double expectedResultSin, double expectedResultCos, double allowedVarianceSin, double allowedVarianceCos) + { + (Vector256 resultSin, Vector256 resultCos) = Vector256.SinCos(Vector256.Create(value)); + AssertEqual(Vector256.Create(expectedResultSin), resultSin, Vector256.Create(allowedVarianceSin)); + AssertEqual(Vector256.Create(expectedResultCos), resultCos, Vector256.Create(allowedVarianceCos)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinCosSingle), MemberType = typeof(GenericMathTestMemberData))] + public void SinCosSingleTest(float value, float expectedResultSin, float expectedResultCos, float allowedVarianceSin, float allowedVarianceCos) + { + (Vector256 resultSin, Vector256 resultCos) = Vector256.SinCos(Vector256.Create(value)); + AssertEqual(Vector256.Create(expectedResultSin), resultSin, Vector256.Create(allowedVarianceSin)); + AssertEqual(Vector256.Create(expectedResultCos), resultCos, Vector256.Create(allowedVarianceCos)); + } + [Theory] [MemberData(nameof(GenericMathTestMemberData.TruncateDouble), MemberType = typeof(GenericMathTestMemberData))] public void TruncateDoubleTest(double value, double expectedResult) diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs index 450abc7f32b86d..f996d82369615f 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs @@ -5273,6 +5273,22 @@ private static void TestCreateSequence(T start, T step) } } + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CosDouble), MemberType = typeof(GenericMathTestMemberData))] + public void CosDoubleTest(double value, double expectedResult, double variance) + { + Vector512 actualResult = Vector512.Cos(Vector512.Create(value)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CosSingle), MemberType = typeof(GenericMathTestMemberData))] + public void CosSingleTest(float value, float expectedResult, float variance) + { + Vector512 actualResult = Vector512.Cos(Vector512.Create(value)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Create(variance)); + } + [Theory] [MemberData(nameof(GenericMathTestMemberData.ExpDouble), MemberType = typeof(GenericMathTestMemberData))] public void ExpDoubleTest(double value, double expectedResult, double variance) @@ -5778,6 +5794,40 @@ public void RoundToEvenSingleTest(float value, float expectedResult) AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); } + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinDouble), MemberType = typeof(GenericMathTestMemberData))] + public void SinDoubleTest(double value, double expectedResult, double variance) + { + Vector512 actualResult = Vector512.Sin(Vector512.Create(value)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinSingle), MemberType = typeof(GenericMathTestMemberData))] + public void SinSingleTest(float value, float expectedResult, float variance) + { + Vector512 actualResult = Vector512.Sin(Vector512.Create(value)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinCosDouble), MemberType = typeof(GenericMathTestMemberData))] + public void SinCosDoubleTest(double value, double expectedResultSin, double expectedResultCos, double allowedVarianceSin, double allowedVarianceCos) + { + (Vector512 resultSin, Vector512 resultCos) = Vector512.SinCos(Vector512.Create(value)); + AssertEqual(Vector512.Create(expectedResultSin), resultSin, Vector512.Create(allowedVarianceSin)); + AssertEqual(Vector512.Create(expectedResultCos), resultCos, Vector512.Create(allowedVarianceCos)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinCosSingle), MemberType = typeof(GenericMathTestMemberData))] + public void SinCosSingleTest(float value, float expectedResultSin, float expectedResultCos, float allowedVarianceSin, float allowedVarianceCos) + { + (Vector512 resultSin, Vector512 resultCos) = Vector512.SinCos(Vector512.Create(value)); + AssertEqual(Vector512.Create(expectedResultSin), resultSin, Vector512.Create(allowedVarianceSin)); + AssertEqual(Vector512.Create(expectedResultCos), resultCos, Vector512.Create(allowedVarianceCos)); + } + [Theory] [MemberData(nameof(GenericMathTestMemberData.TruncateDouble), MemberType = typeof(GenericMathTestMemberData))] public void TruncateDoubleTest(double value, double expectedResult) diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs index ba7ee7c8917874..c049c08515a083 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs @@ -4241,6 +4241,22 @@ private static void TestCreateSequence(T start, T step) } } + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CosDouble), MemberType = typeof(GenericMathTestMemberData))] + public void CosDoubleTest(double value, double expectedResult, double variance) + { + Vector64 actualResult = Vector64.Cos(Vector64.Create(value)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CosSingle), MemberType = typeof(GenericMathTestMemberData))] + public void CosSingleTest(float value, float expectedResult, float variance) + { + Vector64 actualResult = Vector64.Cos(Vector64.Create(value)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Create(variance)); + } + [Theory] [MemberData(nameof(GenericMathTestMemberData.ExpDouble), MemberType = typeof(GenericMathTestMemberData))] public void ExpDoubleTest(double value, double expectedResult, double variance) @@ -4736,6 +4752,40 @@ public void RoundToEvenSingleTest(float value, float expectedResult) AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); } + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinDouble), MemberType = typeof(GenericMathTestMemberData))] + public void SinDoubleTest(double value, double expectedResult, double variance) + { + Vector64 actualResult = Vector64.Sin(Vector64.Create(value)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinSingle), MemberType = typeof(GenericMathTestMemberData))] + public void SinSingleTest(float value, float expectedResult, float variance) + { + Vector64 actualResult = Vector64.Sin(Vector64.Create(value)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinCosDouble), MemberType = typeof(GenericMathTestMemberData))] + public void SinCosDoubleTest(double value, double expectedResultSin, double expectedResultCos, double allowedVarianceSin, double allowedVarianceCos) + { + (Vector64 resultSin, Vector64 resultCos) = Vector64.SinCos(Vector64.Create(value)); + AssertEqual(Vector64.Create(expectedResultSin), resultSin, Vector64.Create(allowedVarianceSin)); + AssertEqual(Vector64.Create(expectedResultCos), resultCos, Vector64.Create(allowedVarianceCos)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.SinCosSingle), MemberType = typeof(GenericMathTestMemberData))] + public void SinCosSingleTest(float value, float expectedResultSin, float expectedResultCos, float allowedVarianceSin, float allowedVarianceCos) + { + (Vector64 resultSin, Vector64 resultCos) = Vector64.SinCos(Vector64.Create(value)); + AssertEqual(Vector64.Create(expectedResultSin), resultSin, Vector64.Create(allowedVarianceSin)); + AssertEqual(Vector64.Create(expectedResultCos), resultCos, Vector64.Create(allowedVarianceCos)); + } + [Theory] [MemberData(nameof(GenericMathTestMemberData.TruncateDouble), MemberType = typeof(GenericMathTestMemberData))] public void TruncateDoubleTest(double value, double expectedResult) diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Math.cs b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Math.cs index 136e4acf1d3735..2550b706b41063 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Math.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Math.cs @@ -473,39 +473,7 @@ public static void Ceiling_Double_IEEE(double value, double expectedResult, doub } [Theory] - [InlineData( double.NegativeInfinity, double.NaN, 0.0)] - [InlineData(-3.1415926535897932, -1.0, CrossPlatformMachineEpsilon * 10)] // value: -(pi) - [InlineData(-2.7182818284590452, -0.91173391478696510, CrossPlatformMachineEpsilon)] // value: -(e) - [InlineData(-2.3025850929940457, -0.66820151019031295, CrossPlatformMachineEpsilon)] // value: -(ln(10)) - [InlineData(-1.5707963267948966, 0.0, CrossPlatformMachineEpsilon)] // value: -(pi / 2) - [InlineData(-1.4426950408889634, 0.12775121753523991, CrossPlatformMachineEpsilon)] // value: -(log2(e)) - [InlineData(-1.4142135623730950, 0.15594369476537447, CrossPlatformMachineEpsilon)] // value: -(sqrt(2)) - [InlineData(-1.1283791670955126, 0.42812514788535792, CrossPlatformMachineEpsilon)] // value: -(2 / sqrt(pi)) - [InlineData(-1.0, 0.54030230586813972, CrossPlatformMachineEpsilon)] - [InlineData(-0.78539816339744831, 0.70710678118654752, CrossPlatformMachineEpsilon)] // value: -(pi / 4), expected: (1 / sqrt(2)) - [InlineData(-0.70710678118654752, 0.76024459707563015, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) - [InlineData(-0.69314718055994531, 0.76923890136397213, CrossPlatformMachineEpsilon)] // value: -(ln(2)) - [InlineData(-0.63661977236758134, 0.80410982822879171, CrossPlatformMachineEpsilon)] // value: -(2 / pi) - [InlineData(-0.43429448190325183, 0.90716712923909839, CrossPlatformMachineEpsilon)] // value: -(log10(e)) - [InlineData(-0.31830988618379067, 0.94976571538163866, CrossPlatformMachineEpsilon)] // value: -(1 / pi) - [InlineData(-0.0, 1.0, CrossPlatformMachineEpsilon * 10)] - [InlineData( double.NaN, double.NaN, 0.0)] - [InlineData( 0.0, 1.0, CrossPlatformMachineEpsilon * 10)] - [InlineData( 0.31830988618379067, 0.94976571538163866, CrossPlatformMachineEpsilon)] // value: (1 / pi) - [InlineData( 0.43429448190325183, 0.90716712923909839, CrossPlatformMachineEpsilon)] // value: (log10(e)) - [InlineData( 0.63661977236758134, 0.80410982822879171, CrossPlatformMachineEpsilon)] // value: (2 / pi) - [InlineData( 0.69314718055994531, 0.76923890136397213, CrossPlatformMachineEpsilon)] // value: (ln(2)) - [InlineData( 0.70710678118654752, 0.76024459707563015, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) - [InlineData( 0.78539816339744831, 0.70710678118654752, CrossPlatformMachineEpsilon)] // value: (pi / 4), expected: (1 / sqrt(2)) - [InlineData( 1.0, 0.54030230586813972, CrossPlatformMachineEpsilon)] - [InlineData( 1.1283791670955126, 0.42812514788535792, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) - [InlineData( 1.4142135623730950, 0.15594369476537447, CrossPlatformMachineEpsilon)] // value: (sqrt(2)) - [InlineData( 1.4426950408889634, 0.12775121753523991, CrossPlatformMachineEpsilon)] // value: (log2(e)) - [InlineData( 1.5707963267948966, 0.0, CrossPlatformMachineEpsilon)] // value: (pi / 2) - [InlineData( 2.3025850929940457, -0.66820151019031295, CrossPlatformMachineEpsilon)] // value: (ln(10)) - [InlineData( 2.7182818284590452, -0.91173391478696510, CrossPlatformMachineEpsilon)] // value: (e) - [InlineData( 3.1415926535897932, -1.0, CrossPlatformMachineEpsilon * 10)] // value: (pi) - [InlineData( double.PositiveInfinity, double.NaN, 0.0)] + [MemberData(nameof(GenericMathTestMemberData.CosDouble), MemberType = typeof(GenericMathTestMemberData))] public static void Cos(double value, double expectedResult, double allowedVariance) { AssertExtensions.Equal(expectedResult, Math.Cos(value), allowedVariance); @@ -1354,80 +1322,14 @@ public static void Sign_Single() } [Theory] - [InlineData( double.NegativeInfinity, double.NaN, 0.0)] - [InlineData(-3.1415926535897932, -0.0, CrossPlatformMachineEpsilon)] // value: -(pi) - [InlineData(-2.7182818284590452, -0.41078129050290870, CrossPlatformMachineEpsilon)] // value: -(e) - [InlineData(-2.3025850929940457, -0.74398033695749319, CrossPlatformMachineEpsilon)] // value: -(ln(10)) - [InlineData(-1.5707963267948966, -1.0, CrossPlatformMachineEpsilon * 10)] // value: -(pi / 2) - [InlineData(-1.4426950408889634, -0.99180624439366372, CrossPlatformMachineEpsilon)] // value: -(log2(e)) - [InlineData(-1.4142135623730950, -0.98776594599273553, CrossPlatformMachineEpsilon)] // value: -(sqrt(2)) - [InlineData(-1.1283791670955126, -0.90371945743584630, CrossPlatformMachineEpsilon)] // value: -(2 / sqrt(pi)) - [InlineData(-1.0, -0.84147098480789651, CrossPlatformMachineEpsilon)] - [InlineData(-0.78539816339744831, -0.70710678118654752, CrossPlatformMachineEpsilon)] // value: -(pi / 4), expected: -(1 / sqrt(2)) - [InlineData(-0.70710678118654752, -0.64963693908006244, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) - [InlineData(-0.69314718055994531, -0.63896127631363480, CrossPlatformMachineEpsilon)] // value: -(ln(2)) - [InlineData(-0.63661977236758134, -0.59448076852482208, CrossPlatformMachineEpsilon)] // value: -(2 / pi) - [InlineData(-0.43429448190325183, -0.42077048331375735, CrossPlatformMachineEpsilon)] // value: -(log10(e)) - [InlineData(-0.31830988618379067, -0.31296179620778659, CrossPlatformMachineEpsilon)] // value: -(1 / pi) - [InlineData(-0.0, -0.0, 0.0)] - [InlineData( double.NaN, double.NaN, 0.0)] - [InlineData( 0.0, 0.0, 0.0)] - [InlineData( 0.31830988618379067, 0.31296179620778659, CrossPlatformMachineEpsilon)] // value: (1 / pi) - [InlineData( 0.43429448190325183, 0.42077048331375735, CrossPlatformMachineEpsilon)] // value: (log10(e)) - [InlineData( 0.63661977236758134, 0.59448076852482208, CrossPlatformMachineEpsilon)] // value: (2 / pi) - [InlineData( 0.69314718055994531, 0.63896127631363480, CrossPlatformMachineEpsilon)] // value: (ln(2)) - [InlineData( 0.70710678118654752, 0.64963693908006244, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) - [InlineData( 0.78539816339744831, 0.70710678118654752, CrossPlatformMachineEpsilon)] // value: (pi / 4), expected: (1 / sqrt(2)) - [InlineData( 1.0, 0.84147098480789651, CrossPlatformMachineEpsilon)] - [InlineData( 1.1283791670955126, 0.90371945743584630, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) - [InlineData( 1.4142135623730950, 0.98776594599273553, CrossPlatformMachineEpsilon)] // value: (sqrt(2)) - [InlineData( 1.4426950408889634, 0.99180624439366372, CrossPlatformMachineEpsilon)] // value: (log2(e)) - [InlineData( 1.5707963267948966, 1.0, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2) - [InlineData( 2.3025850929940457, 0.74398033695749319, CrossPlatformMachineEpsilon)] // value: (ln(10)) - [InlineData( 2.7182818284590452, 0.41078129050290870, CrossPlatformMachineEpsilon)] // value: (e) - [InlineData( 3.1415926535897932, 0.0, CrossPlatformMachineEpsilon)] // value: (pi) - [InlineData( double.PositiveInfinity, double.NaN, 0.0)] + [MemberData(nameof(GenericMathTestMemberData.SinDouble), MemberType = typeof(GenericMathTestMemberData))] public static void Sin(double value, double expectedResult, double allowedVariance) { AssertExtensions.Equal(expectedResult, Math.Sin(value), allowedVariance); } [Theory] - [InlineData( double.NegativeInfinity, double.NaN, double.NaN, 0.0, 0.0)] - [InlineData(-1e18, 0.9929693207404051, 0.11837199021871073, 0.0002, 0.002)] // https://github.com/dotnet/runtime/issues/98204 - [InlineData(-3.1415926535897932, -0.0, -1.0, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon * 10)] // value: -(pi) - [InlineData(-2.7182818284590452, -0.41078129050290870, -0.91173391478696510, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(e) - [InlineData(-2.3025850929940457, -0.74398033695749319, -0.66820151019031295, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(ln(10)) - [InlineData(-1.5707963267948966, -1.0, 0.0, CrossPlatformMachineEpsilon * 10, CrossPlatformMachineEpsilon)] // value: -(pi / 2) - [InlineData(-1.4426950408889634, -0.99180624439366372, 0.12775121753523991, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(log2(e)) - [InlineData(-1.4142135623730950, -0.98776594599273553, 0.15594369476537447, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(sqrt(2)) - [InlineData(-1.1283791670955126, -0.90371945743584630, 0.42812514788535792, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(2 / sqrt(pi)) - [InlineData(-1.0, -0.84147098480789651, 0.54030230586813972, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] - [InlineData(-0.78539816339744831, -0.70710678118654752, 0.70710678118654752, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(pi / 4), expected_sin: -(1 / sqrt(2)), expected_cos: 1 - [InlineData(-0.70710678118654752, -0.64963693908006244, 0.76024459707563015, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) - [InlineData(-0.69314718055994531, -0.63896127631363480, 0.76923890136397213, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(ln(2)) - [InlineData(-0.63661977236758134, -0.59448076852482208, 0.80410982822879171, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(2 / pi) - [InlineData(-0.43429448190325183, -0.42077048331375735, 0.90716712923909839, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(log10(e)) - [InlineData(-0.31830988618379067, -0.31296179620778659, 0.94976571538163866, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(1 / pi) - [InlineData(-0.0, -0.0, 1.0, 0.0, CrossPlatformMachineEpsilon * 10)] - [InlineData( double.NaN, double.NaN, double.NaN, 0.0, 0.0)] - [InlineData( 0.0, 0.0, 1.0, 0.0, CrossPlatformMachineEpsilon * 10)] - [InlineData( 0.31830988618379067, 0.31296179620778659, 0.94976571538163866, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (1 / pi) - [InlineData( 0.43429448190325183, 0.42077048331375735, 0.90716712923909839, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (log10(e)) - [InlineData( 0.63661977236758134, 0.59448076852482208, 0.80410982822879171, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (2 / pi) - [InlineData( 0.69314718055994531, 0.63896127631363480, 0.76923890136397213, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (ln(2)) - [InlineData( 0.70710678118654752, 0.64963693908006244, 0.76024459707563015, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) - [InlineData( 0.78539816339744831, 0.70710678118654752, 0.70710678118654752, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (pi / 4), expected_sin: (1 / sqrt(2)), expected_cos: 1 - [InlineData( 1.0, 0.84147098480789651, 0.54030230586813972, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] - [InlineData( 1.1283791670955126, 0.90371945743584630, 0.42812514788535792, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) - [InlineData( 1.4142135623730950, 0.98776594599273553, 0.15594369476537447, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (sqrt(2)) - [InlineData( 1.4426950408889634, 0.99180624439366372, 0.12775121753523991, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (log2(e)) - [InlineData( 1.5707963267948966, 1.0, 0.0, CrossPlatformMachineEpsilon * 10, CrossPlatformMachineEpsilon)] // value: (pi / 2) - [InlineData( 2.3025850929940457, 0.74398033695749319, -0.66820151019031295, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (ln(10)) - [InlineData( 2.7182818284590452, 0.41078129050290870, -0.91173391478696510, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (e) - [InlineData( 3.1415926535897932, 0.0, -1.0, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon * 10)] // value: (pi) - [InlineData( 1e18, -0.9929693207404051, 0.11837199021871073, 0.0002, 0.002)] // https://github.com/dotnet/runtime/issues/98204 - [InlineData( double.PositiveInfinity, double.NaN, double.NaN, 0.0, 0.0)] + [MemberData(nameof(GenericMathTestMemberData.SinCosDouble), MemberType = typeof(GenericMathTestMemberData))] public static void SinCos(double value, double expectedResultSin, double expectedResultCos, double allowedVarianceSin, double allowedVarianceCos) { (double resultSin, double resultCos) = Math.SinCos(value); diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/MathF.cs b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/MathF.cs index 565c00a986b294..1363a2b407b016 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/MathF.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/MathF.cs @@ -584,39 +584,7 @@ public static void CopySign(float x, float y, float expectedResult) } [Theory] - [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] - [InlineData(-3.14159265f, -1.0f, CrossPlatformMachineEpsilon * 10)] // value: -(pi) - [InlineData(-2.71828183f, -0.911733918f, CrossPlatformMachineEpsilon)] // value: -(e) - [InlineData(-2.30258509f, -0.668201510f, CrossPlatformMachineEpsilon)] // value: -(ln(10)) - [InlineData(-1.57079633f, 0.0f, CrossPlatformMachineEpsilon)] // value: -(pi / 2) - [InlineData(-1.44269504f, 0.127751218f, CrossPlatformMachineEpsilon)] // value: -(log2(e)) - [InlineData(-1.41421356f, 0.155943695f, CrossPlatformMachineEpsilon)] // value: -(sqrt(2)) - [InlineData(-1.12837917f, 0.428125148f, CrossPlatformMachineEpsilon)] // value: -(2 / sqrt(pi)) - [InlineData(-1.0f, 0.540302306f, CrossPlatformMachineEpsilon)] - [InlineData(-0.785398163f, 0.707106781f, CrossPlatformMachineEpsilon)] // value: -(pi / 4), expected: (1 / sqrt(2)) - [InlineData(-0.707106781f, 0.760244597f, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) - [InlineData(-0.693147181f, 0.769238901f, CrossPlatformMachineEpsilon)] // value: -(ln(2)) - [InlineData(-0.636619772f, 0.804109828f, CrossPlatformMachineEpsilon)] // value: -(2 / pi) - [InlineData(-0.434294482f, 0.907167129f, CrossPlatformMachineEpsilon)] // value: -(log10(e)) - [InlineData(-0.318309886f, 0.949765715f, CrossPlatformMachineEpsilon)] // value: -(1 / pi) - [InlineData(-0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] - [InlineData(float.NaN, float.NaN, 0.0f)] - [InlineData(0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] - [InlineData(0.318309886f, 0.949765715f, CrossPlatformMachineEpsilon)] // value: (1 / pi) - [InlineData(0.434294482f, 0.907167129f, CrossPlatformMachineEpsilon)] // value: (log10(e)) - [InlineData(0.636619772f, 0.804109828f, CrossPlatformMachineEpsilon)] // value: (2 / pi) - [InlineData(0.693147181f, 0.769238901f, CrossPlatformMachineEpsilon)] // value: (ln(2)) - [InlineData(0.707106781f, 0.760244597f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) - [InlineData(0.785398163f, 0.707106781f, CrossPlatformMachineEpsilon)] // value: (pi / 4), expected: (1 / sqrt(2)) - [InlineData(1.0f, 0.540302306f, CrossPlatformMachineEpsilon)] - [InlineData(1.12837917f, 0.428125148f, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) - [InlineData(1.41421356f, 0.155943695f, CrossPlatformMachineEpsilon)] // value: (sqrt(2)) - [InlineData(1.44269504f, 0.127751218f, CrossPlatformMachineEpsilon)] // value: (log2(e)) - [InlineData(1.57079633f, 0.0f, CrossPlatformMachineEpsilon)] // value: (pi / 2) - [InlineData(2.30258509f, -0.668201510f, CrossPlatformMachineEpsilon)] // value: (ln(10)) - [InlineData(2.71828183f, -0.911733918f, CrossPlatformMachineEpsilon)] // value: (e) - [InlineData(3.14159265f, -1.0f, CrossPlatformMachineEpsilon * 10)] // value: (pi) - [InlineData(float.PositiveInfinity, float.NaN, 0.0f)] + [MemberData(nameof(GenericMathTestMemberData.CosSingle), MemberType = typeof(GenericMathTestMemberData))] public static void Cos(float value, float expectedResult, float allowedVariance) { AssertExtensions.Equal(expectedResult, MathF.Cos(value), allowedVariance); @@ -1349,80 +1317,14 @@ public static void Sign() } [Theory] - [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] - [InlineData(-3.14159265f, -0.0f, CrossPlatformMachineEpsilon)] // value: -(pi) - [InlineData(-2.71828183f, -0.410781291f, CrossPlatformMachineEpsilon)] // value: -(e) - [InlineData(-2.30258509f, -0.743980337f, CrossPlatformMachineEpsilon)] // value: -(ln(10)) - [InlineData(-1.57079633f, -1.0f, CrossPlatformMachineEpsilon * 10)] // value: -(pi / 2) - [InlineData(-1.44269504f, -0.991806244f, CrossPlatformMachineEpsilon)] // value: -(log2(e)) - [InlineData(-1.41421356f, -0.987765946f, CrossPlatformMachineEpsilon)] // value: -(sqrt(2)) - [InlineData(-1.12837917f, -0.903719457f, CrossPlatformMachineEpsilon)] // value: -(2 / sqrt(pi)) - [InlineData(-1.0f, -0.841470985f, CrossPlatformMachineEpsilon)] - [InlineData(-0.785398163f, -0.707106781f, CrossPlatformMachineEpsilon)] // value: -(pi / 4), expected: -(1 / sqrt(2)) - [InlineData(-0.707106781f, -0.649636939f, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) - [InlineData(-0.693147181f, -0.638961276f, CrossPlatformMachineEpsilon)] // value: -(ln(2)) - [InlineData(-0.636619772f, -0.594480769f, CrossPlatformMachineEpsilon)] // value: -(2 / pi) - [InlineData(-0.434294482f, -0.420770483f, CrossPlatformMachineEpsilon)] // value: -(log10(e)) - [InlineData(-0.318309886f, -0.312961796f, CrossPlatformMachineEpsilon)] // value: -(1 / pi) - [InlineData(-0.0f, -0.0f, 0.0f)] - [InlineData(float.NaN, float.NaN, 0.0f)] - [InlineData(0.0f, 0.0f, 0.0f)] - [InlineData(0.318309886f, 0.312961796f, CrossPlatformMachineEpsilon)] // value: (1 / pi) - [InlineData(0.434294482f, 0.420770483f, CrossPlatformMachineEpsilon)] // value: (log10(e)) - [InlineData(0.636619772f, 0.594480769f, CrossPlatformMachineEpsilon)] // value: (2 / pi) - [InlineData(0.693147181f, 0.638961276f, CrossPlatformMachineEpsilon)] // value: (ln(2)) - [InlineData(0.707106781f, 0.649636939f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) - [InlineData(0.785398163f, 0.707106781f, CrossPlatformMachineEpsilon)] // value: (pi / 4), expected: (1 / sqrt(2)) - [InlineData(1.0f, 0.841470985f, CrossPlatformMachineEpsilon)] - [InlineData(1.12837917f, 0.903719457f, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) - [InlineData(1.41421356f, 0.987765946f, CrossPlatformMachineEpsilon)] // value: (sqrt(2)) - [InlineData(1.44269504f, 0.991806244f, CrossPlatformMachineEpsilon)] // value: (log2(e)) - [InlineData(1.57079633f, 1.0f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2) - [InlineData(2.30258509f, 0.743980337f, CrossPlatformMachineEpsilon)] // value: (ln(10)) - [InlineData(2.71828183f, 0.410781291f, CrossPlatformMachineEpsilon)] // value: (e) - [InlineData(3.14159265f, 0.0f, CrossPlatformMachineEpsilon)] // value: (pi) - [InlineData(float.PositiveInfinity, float.NaN, 0.0f)] + [MemberData(nameof(GenericMathTestMemberData.SinSingle), MemberType = typeof(GenericMathTestMemberData))] public static void Sin(float value, float expectedResult, float allowedVariance) { AssertExtensions.Equal(expectedResult, MathF.Sin(value), allowedVariance); } [Theory] - [InlineData( float.NegativeInfinity, float.NaN, float.NaN, 0.0f, 0.0f)] - [InlineData(-1e8f, -0.931639, -0.36338508, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // https://github.com/dotnet/runtime/issues/98204 - [InlineData(-3.14159265f, -0.0f, -1.0f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon * 10)] // value: -(pi) - [InlineData(-2.71828183f, -0.410781291f, -0.911733918f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(e) - [InlineData(-2.30258509f, -0.743980337f, -0.668201510f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(ln(10)) - [InlineData(-1.57079633f, -1.0f, 0.0f, CrossPlatformMachineEpsilon * 10, CrossPlatformMachineEpsilon)] // value: -(pi / 2) - [InlineData(-1.44269504f, -0.991806244f, 0.127751218f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(log2(e)) - [InlineData(-1.41421356f, -0.987765946f, 0.155943695f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(sqrt(2)) - [InlineData(-1.12837917f, -0.903719457f, 0.428125148f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(2 / sqrt(pi)) - [InlineData(-1.0f, -0.841470985f, 0.540302306f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] - [InlineData(-0.785398163f, -0.707106781f, 0.707106781f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(pi / 4), expected_sin: -(1 / sqrt(2)), expected_cos: 1 - [InlineData(-0.707106781f, -0.649636939f, 0.760244597f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) - [InlineData(-0.693147181f, -0.638961276f, 0.769238901f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(ln(2)) - [InlineData(-0.636619772f, -0.594480769f, 0.804109828f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(2 / pi) - [InlineData(-0.434294482f, -0.420770483f, 0.907167129f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(log10(e)) - [InlineData(-0.318309886f, -0.312961796f, 0.949765715f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: -(1 / pi) - [InlineData(-0.0f, -0.0f, 1.0f, 0.0f, CrossPlatformMachineEpsilon * 10)] - [InlineData( float.NaN, float.NaN, float.NaN, 0.0f, 0.0f)] - [InlineData( 0.0f, 0.0f, 1.0f, 0.0f, CrossPlatformMachineEpsilon * 10)] - [InlineData( 0.318309886f, 0.312961796f, 0.949765715f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (1 / pi) - [InlineData( 0.434294482f, 0.420770483f, 0.907167129f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (log10(e)) - [InlineData( 0.636619772f, 0.594480769f, 0.804109828f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (2 / pi) - [InlineData( 0.693147181f, 0.638961276f, 0.769238901f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (ln(2)) - [InlineData( 0.707106781f, 0.649636939f, 0.760244597f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) - [InlineData( 0.785398163f, 0.707106781f, 0.707106781f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (pi / 4), expected_sin: (1 / sqrt(2)), expected_cos: 1 - [InlineData( 1.0f, 0.841470985f, 0.540302306f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] - [InlineData( 1.12837917f, 0.903719457f, 0.428125148f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) - [InlineData( 1.41421356f, 0.987765946f, 0.155943695f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (sqrt(2)) - [InlineData( 1.44269504f, 0.991806244f, 0.127751218f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (log2(e)) - [InlineData( 1.57079633f, 1.0f, 0.0f, CrossPlatformMachineEpsilon * 10, CrossPlatformMachineEpsilon)] // value: (pi / 2) - [InlineData( 2.30258509f, 0.743980337f, -0.668201510f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (ln(10)) - [InlineData( 2.71828183f, 0.410781291f, -0.911733918f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // value: (e) - [InlineData( 3.14159265f, 0.0f, -1.0f, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon * 10)] // value: (pi) - [InlineData( 1e8f, 0.931639, -0.36338508, CrossPlatformMachineEpsilon, CrossPlatformMachineEpsilon)] // https://github.com/dotnet/runtime/issues/98204 - [InlineData( float.PositiveInfinity, float.NaN, float.NaN, 0.0f, 0.0f)] + [MemberData(nameof(GenericMathTestMemberData.SinCosSingle), MemberType = typeof(GenericMathTestMemberData))] public static void SinCos(float value, float expectedResultSin, float expectedResultCos, float allowedVarianceSin, float allowedVarianceCos) { (float resultSin, float resultCos) = MathF.SinCos(value);