diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Cosh.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Cosh.cs index 2047ee6a26f5cb..a3088ff1f36779 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Cosh.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Cosh.cs @@ -58,10 +58,12 @@ public static void Cosh(ReadOnlySpan x, Span destination) // // coshf = v/2 * exp(x - log(v)) where v = 0x1.0000e8p-1 + private const uint Single_MAX_VECTORIZED_VALUE = 0x4E8565AAu; private const float Single_LOGV = 0.693161f; private const float Single_HALFV = 1.0000138f; private const float Single_INVV2 = 0.24999309f; + private const ulong Double_MAX_VECTORIZED_VALUE = 0x4030800000000000ul; private const double Double_LOGV = 0.6931471805599453; private const double Double_HALFV = 1.0; private const double Double_INVV2 = 0.25; @@ -75,17 +77,27 @@ public static Vector128 Invoke(Vector128 t) if (typeof(T) == typeof(float)) { Vector128 x = t.AsSingle(); - Vector128 y = Vector128.Abs(x); - Vector128 z = ExpOperator.Invoke(y - Vector128.Create((float)Single_LOGV)); - return (Vector128.Create((float)Single_HALFV) * (z + (Vector128.Create((float)Single_INVV2) / z))).As(); + + if (Vector128.GreaterThanAny(y.AsUInt32(), Vector128.Create(Single_MAX_VECTORIZED_VALUE))) + { + return ApplyScalar>(x).As(); + } + + Vector128 z = ExpOperator.Invoke(y - Vector128.Create(Single_LOGV)); + return (Vector128.Create(Single_HALFV) * (z + (Vector128.Create(Single_INVV2) / z))).As(); } else { Debug.Assert(typeof(T) == typeof(double)); Vector128 x = t.AsDouble(); - Vector128 y = Vector128.Abs(x); + + if (Vector128.GreaterThanAny(y.AsUInt64(), Vector128.Create(Double_MAX_VECTORIZED_VALUE))) + { + return ApplyScalar>(x).As(); + } + Vector128 z = ExpOperator.Invoke(y - Vector128.Create(Double_LOGV)); return (Vector128.Create(Double_HALFV) * (z + (Vector128.Create(Double_INVV2) / z))).As(); } @@ -96,17 +108,27 @@ public static Vector256 Invoke(Vector256 t) if (typeof(T) == typeof(float)) { Vector256 x = t.AsSingle(); - Vector256 y = Vector256.Abs(x); - Vector256 z = ExpOperator.Invoke(y - Vector256.Create((float)Single_LOGV)); - return (Vector256.Create((float)Single_HALFV) * (z + (Vector256.Create((float)Single_INVV2) / z))).As(); + + if (Vector256.GreaterThanAny(y.AsUInt32(), Vector256.Create(Single_MAX_VECTORIZED_VALUE))) + { + return ApplyScalar>(x).As(); + } + + Vector256 z = ExpOperator.Invoke(y - Vector256.Create(Single_LOGV)); + return (Vector256.Create(Single_HALFV) * (z + (Vector256.Create(Single_INVV2) / z))).As(); } else { Debug.Assert(typeof(T) == typeof(double)); Vector256 x = t.AsDouble(); - Vector256 y = Vector256.Abs(x); + + if (Vector256.GreaterThanAny(y.AsUInt64(), Vector256.Create(Double_MAX_VECTORIZED_VALUE))) + { + return ApplyScalar>(x).As(); + } + Vector256 z = ExpOperator.Invoke(y - Vector256.Create(Double_LOGV)); return (Vector256.Create(Double_HALFV) * (z + (Vector256.Create(Double_INVV2) / z))).As(); } @@ -117,17 +139,27 @@ public static Vector512 Invoke(Vector512 t) if (typeof(T) == typeof(float)) { Vector512 x = t.AsSingle(); - Vector512 y = Vector512.Abs(x); - Vector512 z = ExpOperator.Invoke(y - Vector512.Create((float)Single_LOGV)); - return (Vector512.Create((float)Single_HALFV) * (z + (Vector512.Create((float)Single_INVV2) / z))).As(); + + if (Vector512.GreaterThanAny(y.AsUInt32(), Vector512.Create(Single_MAX_VECTORIZED_VALUE))) + { + return ApplyScalar>(x).As(); + } + + Vector512 z = ExpOperator.Invoke(y - Vector512.Create(Single_LOGV)); + return (Vector512.Create(Single_HALFV) * (z + (Vector512.Create(Single_INVV2) / z))).As(); } else { Debug.Assert(typeof(T) == typeof(double)); Vector512 x = t.AsDouble(); - Vector512 y = Vector512.Abs(x); + + if (Vector512.GreaterThanAny(y.AsUInt64(), Vector512.Create(Double_MAX_VECTORIZED_VALUE))) + { + return ApplyScalar>(x).As(); + } + Vector512 z = ExpOperator.Invoke(y - Vector512.Create(Double_LOGV)); return (Vector512.Create(Double_HALFV) * (z + (Vector512.Create(Double_INVV2) / z))).As(); } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Sinh.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Sinh.cs index a154e3d9edce9d..e6586bdd1e4006 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Sinh.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Sinh.cs @@ -40,10 +40,12 @@ public static void Sinh(ReadOnlySpan x, Span destination) // Same as cosh, but with `z -` rather than `z +`, and with the sign // flipped on the result based on the sign of the input. + private const uint Single_MAX_VECTORIZED_VALUE = 0x4E8565AAu; private const float Single_LOGV = 0.693161f; private const float Single_HALFV = 1.0000138f; private const float Single_INVV2 = 0.24999309f; + private const ulong Double_MAX_VECTORIZED_VALUE = 0x4030800000000000ul; private const double Double_LOGV = 0.6931471805599453; private const double Double_HALFV = 1.0; private const double Double_INVV2 = 0.25; @@ -57,10 +59,15 @@ public static Vector128 Invoke(Vector128 t) if (typeof(T) == typeof(float)) { Vector128 x = t.AsSingle(); - Vector128 y = Vector128.Abs(x); - Vector128 z = ExpOperator.Invoke(y - Vector128.Create((float)Single_LOGV)); - Vector128 result = Vector128.Create((float)Single_HALFV) * (z - (Vector128.Create((float)Single_INVV2) / z)); + + if (Vector128.GreaterThanAny(y.AsUInt32(), Vector128.Create(Single_MAX_VECTORIZED_VALUE))) + { + return ApplyScalar>(x).As(); + } + + Vector128 z = ExpOperator.Invoke(y - Vector128.Create(Single_LOGV)); + Vector128 result = Vector128.Create(Single_HALFV) * (z - (Vector128.Create(Single_INVV2) / z)); Vector128 sign = x.AsUInt32() & Vector128.Create(~(uint)int.MaxValue); return (sign ^ result.AsUInt32()).As(); } @@ -68,8 +75,13 @@ public static Vector128 Invoke(Vector128 t) { Debug.Assert(typeof(T) == typeof(double)); Vector128 x = t.AsDouble(); - Vector128 y = Vector128.Abs(x); + + if (Vector128.GreaterThanAny(y.AsUInt64(), Vector128.Create(Double_MAX_VECTORIZED_VALUE))) + { + return ApplyScalar>(x).As(); + } + Vector128 z = ExpOperator.Invoke(y - Vector128.Create(Double_LOGV)); Vector128 result = Vector128.Create(Double_HALFV) * (z - (Vector128.Create(Double_INVV2) / z)); Vector128 sign = x.AsUInt64() & Vector128.Create(~(ulong)long.MaxValue); @@ -82,10 +94,15 @@ public static Vector256 Invoke(Vector256 t) if (typeof(T) == typeof(float)) { Vector256 x = t.AsSingle(); - Vector256 y = Vector256.Abs(x); - Vector256 z = ExpOperator.Invoke(y - Vector256.Create((float)Single_LOGV)); - Vector256 result = Vector256.Create((float)Single_HALFV) * (z - (Vector256.Create((float)Single_INVV2) / z)); + + if (Vector256.GreaterThanAny(y.AsUInt32(), Vector256.Create(Single_MAX_VECTORIZED_VALUE))) + { + return ApplyScalar>(x).As(); + } + + Vector256 z = ExpOperator.Invoke(y - Vector256.Create(Single_LOGV)); + Vector256 result = Vector256.Create(Single_HALFV) * (z - (Vector256.Create(Single_INVV2) / z)); Vector256 sign = x.AsUInt32() & Vector256.Create(~(uint)int.MaxValue); return (sign ^ result.AsUInt32()).As(); } @@ -93,8 +110,13 @@ public static Vector256 Invoke(Vector256 t) { Debug.Assert(typeof(T) == typeof(double)); Vector256 x = t.AsDouble(); - Vector256 y = Vector256.Abs(x); + + if (Vector256.GreaterThanAny(y.AsUInt64(), Vector256.Create(Double_MAX_VECTORIZED_VALUE))) + { + return ApplyScalar>(x).As(); + } + Vector256 z = ExpOperator.Invoke(y - Vector256.Create(Double_LOGV)); Vector256 result = Vector256.Create(Double_HALFV) * (z - (Vector256.Create(Double_INVV2) / z)); Vector256 sign = x.AsUInt64() & Vector256.Create(~(ulong)long.MaxValue); @@ -107,10 +129,15 @@ public static Vector512 Invoke(Vector512 t) if (typeof(T) == typeof(float)) { Vector512 x = t.AsSingle(); - Vector512 y = Vector512.Abs(x); - Vector512 z = ExpOperator.Invoke(y - Vector512.Create((float)Single_LOGV)); - Vector512 result = Vector512.Create((float)Single_HALFV) * (z - (Vector512.Create((float)Single_INVV2) / z)); + + if (Vector512.GreaterThanAny(y.AsUInt32(), Vector512.Create(Single_MAX_VECTORIZED_VALUE))) + { + return ApplyScalar>(x).As(); + } + + Vector512 z = ExpOperator.Invoke(y - Vector512.Create(Single_LOGV)); + Vector512 result = Vector512.Create(Single_HALFV) * (z - (Vector512.Create(Single_INVV2) / z)); Vector512 sign = x.AsUInt32() & Vector512.Create(~(uint)int.MaxValue); return (sign ^ result.AsUInt32()).As(); } @@ -118,8 +145,13 @@ public static Vector512 Invoke(Vector512 t) { Debug.Assert(typeof(T) == typeof(double)); Vector512 x = t.AsDouble(); - Vector512 y = Vector512.Abs(x); + + if (Vector512.GreaterThanAny(y.AsUInt64(), Vector512.Create(Double_MAX_VECTORIZED_VALUE))) + { + return ApplyScalar>(x).As(); + } + Vector512 z = ExpOperator.Invoke(y - Vector512.Create(Double_LOGV)); Vector512 result = Vector512.Create(Double_HALFV) * (z - (Vector512.Create(Double_INVV2) / z)); Vector512 sign = x.AsUInt64() & Vector512.Create(~(ulong)long.MaxValue); diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorPrimitives.Generic.cs b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitives.Generic.cs index cba1f4f1b95ea2..38e60dab107f3c 100644 --- a/src/libraries/System.Numerics.Tensors/tests/TensorPrimitives.Generic.cs +++ b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitives.Generic.cs @@ -367,8 +367,7 @@ public static IEnumerable SpanDestinationFunctionsToTest() yield return Create(TensorPrimitives.Cbrt, T.Cbrt, Helpers.DetermineTolerance(doubleTolerance: 1e-13)); yield return Create(TensorPrimitives.Ceiling, T.Ceiling); yield return Create(TensorPrimitives.Cos, T.Cos, trigTolerance); - // TODO https://github.com/dotnet/runtime/issues/98861 - yield return Create(TensorPrimitives.Cosh, T.Cosh, Helpers.DetermineTolerance(doubleTolerance: 1e-14)); + yield return Create(TensorPrimitives.Cosh, T.Cosh); // TODO https://github.com/dotnet/runtime/issues/98861 yield return Create(TensorPrimitives.CosPi, T.CosPi, trigTolerance ?? Helpers.DetermineTolerance(floatTolerance: 1e-5f)); yield return Create(TensorPrimitives.DegreesToRadians, T.DegreesToRadians); @@ -396,8 +395,7 @@ public static IEnumerable SpanDestinationFunctionsToTest() yield return Create(TensorPrimitives.ReciprocalSqrtEstimate, T.ReciprocalSqrtEstimate, T.CreateTruncating(Helpers.DefaultToleranceForEstimates)); yield return Create(TensorPrimitives.Round, T.Round); yield return Create(TensorPrimitives.Sin, T.Sin, trigTolerance); - // TODO https://github.com/dotnet/runtime/issues/98861 - yield return Create(TensorPrimitives.Sinh, T.Sinh, Helpers.DetermineTolerance(doubleTolerance: 1e-14)); + yield return Create(TensorPrimitives.Sinh, T.Sinh); // TODO https://github.com/dotnet/runtime/issues/98861 yield return Create(TensorPrimitives.SinPi, T.SinPi, Helpers.DetermineTolerance(doubleTolerance: 1e-13, floatTolerance: 1e-4f)); yield return Create(TensorPrimitives.Sqrt, T.Sqrt); @@ -521,7 +519,7 @@ public static IEnumerable SpanSpanDestinationFunctionsToTest() yield return Create(TensorPrimitives.Ieee754Remainder, T.Ieee754Remainder); yield return Create(TensorPrimitives.Log, T.Log); // TODO https://github.com/dotnet/runtime/issues/98861 - yield return Create(TensorPrimitives.Pow, T.Pow, Helpers.DetermineTolerance(doubleTolerance: 1e-13, floatTolerance: 1e-4f)); + yield return Create(TensorPrimitives.Pow, T.Pow, Helpers.DetermineTolerance(doubleTolerance: 1e-13, floatTolerance: 1e-5f)); static object[] Create(SpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) => new object[] { tensorPrimitivesMethod, expectedMethod, tolerance }; @@ -651,7 +649,7 @@ public static IEnumerable SpanScalarDestinationFunctionsToTest() yield return Create(TensorPrimitives.CopySign, T.CopySign); yield return Create(TensorPrimitives.Ieee754Remainder, T.Ieee754Remainder); // TODO https://github.com/dotnet/runtime/issues/98861 - yield return Create(TensorPrimitives.Pow, T.Pow, Helpers.DetermineTolerance(doubleTolerance: 1e-13, floatTolerance: 1e-4f)); + yield return Create(TensorPrimitives.Pow, T.Pow, Helpers.DetermineTolerance(doubleTolerance: 1e-13, floatTolerance: 1e-5f)); yield return Create(TensorPrimitives.Log, T.Log); yield return Create(TensorPrimitives.Max, T.Max); yield return Create(TensorPrimitives.MaxMagnitude, T.MaxMagnitude); @@ -756,7 +754,7 @@ public static IEnumerable ScalarSpanFloatDestinationFunctionsToTest() yield return Create(TensorPrimitives.Atan2, T.Atan2); yield return Create(TensorPrimitives.Atan2Pi, T.Atan2Pi); // TODO https://github.com/dotnet/runtime/issues/98861 - yield return Create(TensorPrimitives.Pow, T.Pow, Helpers.DetermineTolerance(floatTolerance: 1e-4f)); + yield return Create(TensorPrimitives.Pow, T.Pow, Helpers.DetermineTolerance(floatTolerance: 1e-5f)); yield return Create(TensorPrimitives.Ieee754Remainder, T.Ieee754Remainder); static object[] Create(ScalarSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.cs b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.cs index 173e57649cf8ee..9b95f61d5fb3cb 100644 --- a/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.cs +++ b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.cs @@ -956,7 +956,7 @@ public void Dot_ThrowsForMismatchedLengths_x_y() public void Dot_AllLengths() { // TODO https://github.com/dotnet/runtime/issues/98861 - T? tolerance = Helpers.DetermineTolerance(doubleTolerance: 1e-14f, floatTolerance: 1e-3f); + T? tolerance = Helpers.DetermineTolerance(doubleTolerance: 1e-14f, floatTolerance: 1e-5f); Assert.All(Helpers.TensorLengthsIncluding0, tensorLength => {