|
7 | 7 | using System.Runtime.Intrinsics; |
8 | 8 | using System.Runtime.Intrinsics.Arm; |
9 | 9 | using System.Runtime.Intrinsics.X86; |
| 10 | +using System.Security.Cryptography; |
10 | 11 |
|
11 | 12 | namespace System.Numerics.Tensors |
12 | 13 | { |
@@ -147,15 +148,15 @@ public static void ConvertToHalf(ReadOnlySpan<float> source, Span<Half> destinat |
147 | 148 | // so we convert the VectorXx<float> to a VectorXx<uint>, and the caller then uses this twice, narrows the combination |
148 | 149 | // into a VectorXx<ushort>, and then saves that out to the destination `ref Half` reinterpreted as `ref ushort`. |
149 | 150 |
|
150 | | - #pragma warning disable IDE0059 // https://github.com/dotnet/roslyn/issues/44948 |
| 151 | +#pragma warning disable IDE0059 // https://github.com/dotnet/roslyn/issues/44948 |
151 | 152 | const uint MinExp = 0x3880_0000u; // Minimum exponent for rounding |
152 | 153 | const uint Exponent126 = 0x3f00_0000u; // Exponent displacement #1 |
153 | 154 | const uint SingleBiasedExponentMask = 0x7F80_0000; // float.BiasedExponentMask; // Exponent mask |
154 | 155 | const uint Exponent13 = 0x0680_0000u; // Exponent displacement #2 |
155 | 156 | const float MaxHalfValueBelowInfinity = 65520.0f; // Maximum value that is not Infinity in Half |
156 | 157 | const uint ExponentMask = 0x7C00; // Mask for exponent bits in Half |
157 | 158 | const uint SingleSignMask = 0x8000_0000u; // float.SignMask; // Mask for sign bit in float |
158 | | - #pragma warning restore IDE0059 |
| 159 | +#pragma warning restore IDE0059 |
159 | 160 |
|
160 | 161 | static Vector128<uint> SingleToHalfAsWidenedUInt32_Vector128(Vector128<float> value) |
161 | 162 | { |
@@ -462,13 +463,13 @@ public static void ConvertToSingle(ReadOnlySpan<Half> source, Span<float> destin |
462 | 463 | // The VectorXx<uint> is created by reading a vector of Halfs as a VectorXx<short> then widened to two VectorXx<int>s and cast to VectorXx<uint>s. |
463 | 464 | // We loop handling one input vector at a time, producing two output float vectors. |
464 | 465 |
|
465 | | - #pragma warning disable IDE0059 // https://github.com/dotnet/roslyn/issues/44948 |
| 466 | +#pragma warning disable IDE0059 // https://github.com/dotnet/roslyn/issues/44948 |
466 | 467 | const uint ExponentLowerBound = 0x3880_0000u; // The smallest positive normal number in Half, converted to Single |
467 | 468 | const uint ExponentOffset = 0x3800_0000u; // BitConverter.SingleToUInt32Bits(1.0f) - ((uint)BitConverter.HalfToUInt16Bits((Half)1.0f) << 13) |
468 | 469 | const uint SingleSignMask = 0x8000_0000; // float.SignMask; // Mask for sign bit in Single |
469 | 470 | const uint HalfExponentMask = 0x7C00; // Mask for exponent bits in Half |
470 | 471 | const uint HalfToSingleBitsMask = 0x0FFF_E000; // Mask for bits in Single converted from Half |
471 | | - #pragma warning restore IDE0059 |
| 472 | +#pragma warning restore IDE0059 |
472 | 473 |
|
473 | 474 | static Vector128<float> HalfAsWidenedUInt32ToSingle_Vector128(Vector128<uint> value) |
474 | 475 | { |
@@ -2992,6 +2993,156 @@ public static Vector512<float> Invoke(Vector512<float> x) |
2992 | 2993 | #endif |
2993 | 2994 | } |
2994 | 2995 |
|
| 2996 | + /// <summary>MathF.Cosh(x)</summary> |
| 2997 | + private readonly struct CoshOperator : IUnaryOperator |
| 2998 | + { |
| 2999 | + // This code is based on `vrs4_coshf` from amd/aocl-libm-ose |
| 3000 | + // Copyright (C) 2008-2022 Advanced Micro Devices, Inc. All rights reserved. |
| 3001 | + // |
| 3002 | + // Licensed under the BSD 3-Clause "New" or "Revised" License |
| 3003 | + // See THIRD-PARTY-NOTICES.TXT for the full license text |
| 3004 | + |
| 3005 | + // Spec: |
| 3006 | + // coshf(|x| > 89.415985107421875) = Infinity |
| 3007 | + // coshf(Infinity) = infinity |
| 3008 | + // coshf(-Infinity) = infinity |
| 3009 | + // |
| 3010 | + // cosh(x) = (exp(x) + exp(-x))/2 |
| 3011 | + // cosh(-x) = +cosh(x) |
| 3012 | + // |
| 3013 | + // checks for special cases |
| 3014 | + // if ( asint(x) > infinity) return x with overflow exception and |
| 3015 | + // return x. |
| 3016 | + // if x is NaN then raise invalid FP operation exception and return x. |
| 3017 | + // |
| 3018 | + // coshf = v/2 * exp(x - log(v)) where v = 0x1.0000e8p-1 |
| 3019 | + |
| 3020 | + private const float LOGV = 0.693161f; |
| 3021 | + private const float HALFV = 1.0000138f; |
| 3022 | + private const float INVV2 = 0.24999309f; |
| 3023 | + |
| 3024 | + public static float Invoke(float x) => MathF.Cosh(x); |
| 3025 | + |
| 3026 | + public static Vector128<float> Invoke(Vector128<float> x) |
| 3027 | + { |
| 3028 | + Vector128<float> y = Vector128.Abs(x); |
| 3029 | + Vector128<float> z = ExpOperator.Invoke(y - Vector128.Create(LOGV)); |
| 3030 | + return Vector128.Create(HALFV) * (z + (Vector128.Create(INVV2) / z)); |
| 3031 | + } |
| 3032 | + |
| 3033 | + public static Vector256<float> Invoke(Vector256<float> x) |
| 3034 | + { |
| 3035 | + Vector256<float> y = Vector256.Abs(x); |
| 3036 | + Vector256<float> z = ExpOperator.Invoke(y - Vector256.Create(LOGV)); |
| 3037 | + return Vector256.Create(HALFV) * (z + (Vector256.Create(INVV2) / z)); |
| 3038 | + } |
| 3039 | + |
| 3040 | +#if NET8_0_OR_GREATER |
| 3041 | + public static Vector512<float> Invoke(Vector512<float> x) |
| 3042 | + { |
| 3043 | + Vector512<float> y = Vector512.Abs(x); |
| 3044 | + Vector512<float> z = ExpOperator.Invoke(y - Vector512.Create(LOGV)); |
| 3045 | + return Vector512.Create(HALFV) * (z + (Vector512.Create(INVV2) / z)); |
| 3046 | + } |
| 3047 | +#endif |
| 3048 | + } |
| 3049 | + |
| 3050 | + /// <summary>MathF.Sinh(x)</summary> |
| 3051 | + private readonly struct SinhOperator : IUnaryOperator |
| 3052 | + { |
| 3053 | + // Same as cosh, but with `z -` rather than `z +`, and with the sign |
| 3054 | + // flipped on the result based on the sign of the input. |
| 3055 | + |
| 3056 | + private const uint SIGN_MASK = 0x7FFFFFFF; |
| 3057 | + private const float LOGV = 0.693161f; |
| 3058 | + private const float HALFV = 1.0000138f; |
| 3059 | + private const float INVV2 = 0.24999309f; |
| 3060 | + |
| 3061 | + public static float Invoke(float x) => MathF.Sinh(x); |
| 3062 | + |
| 3063 | + public static Vector128<float> Invoke(Vector128<float> x) |
| 3064 | + { |
| 3065 | + Vector128<float> y = Vector128.Abs(x); |
| 3066 | + Vector128<float> z = ExpOperator.Invoke(y - Vector128.Create(LOGV)); |
| 3067 | + Vector128<float> result = Vector128.Create(HALFV) * (z - (Vector128.Create(INVV2) / z)); |
| 3068 | + Vector128<uint> sign = x.AsUInt32() & Vector128.Create(~SIGN_MASK); |
| 3069 | + return (sign ^ result.AsUInt32()).AsSingle(); |
| 3070 | + } |
| 3071 | + |
| 3072 | + public static Vector256<float> Invoke(Vector256<float> x) |
| 3073 | + { |
| 3074 | + Vector256<float> y = Vector256.Abs(x); |
| 3075 | + Vector256<float> z = ExpOperator.Invoke(y - Vector256.Create(LOGV)); |
| 3076 | + Vector256<float> result = Vector256.Create(HALFV) * (z - (Vector256.Create(INVV2) / z)); |
| 3077 | + Vector256<uint> sign = x.AsUInt32() & Vector256.Create(~SIGN_MASK); |
| 3078 | + return (sign ^ result.AsUInt32()).AsSingle(); |
| 3079 | + } |
| 3080 | + |
| 3081 | +#if NET8_0_OR_GREATER |
| 3082 | + public static Vector512<float> Invoke(Vector512<float> x) |
| 3083 | + { |
| 3084 | + Vector512<float> y = Vector512.Abs(x); |
| 3085 | + Vector512<float> z = ExpOperator.Invoke(y - Vector512.Create(LOGV)); |
| 3086 | + Vector512<float> result = Vector512.Create(HALFV) * (z - (Vector512.Create(INVV2) / z)); |
| 3087 | + Vector512<uint> sign = x.AsUInt32() & Vector512.Create(~SIGN_MASK); |
| 3088 | + return (sign ^ result.AsUInt32()).AsSingle(); |
| 3089 | + } |
| 3090 | +#endif |
| 3091 | + } |
| 3092 | + |
| 3093 | + /// <summary>MathF.Tanh(x)</summary> |
| 3094 | + private readonly struct TanhOperator : IUnaryOperator |
| 3095 | + { |
| 3096 | + // This code is based on `vrs4_tanhf` from amd/aocl-libm-ose |
| 3097 | + // Copyright (C) 2008-2022 Advanced Micro Devices, Inc. All rights reserved. |
| 3098 | + // |
| 3099 | + // Licensed under the BSD 3-Clause "New" or "Revised" License |
| 3100 | + // See THIRD-PARTY-NOTICES.TXT for the full license text |
| 3101 | + |
| 3102 | + // To compute vrs4_tanhf(v_f32x4_t x) |
| 3103 | + // Let y = |x| |
| 3104 | + // If 0 <= y < 0x1.154246p3 |
| 3105 | + // Let z = e^(-2.0 * y) - 1 -(1) |
| 3106 | + // |
| 3107 | + // Using (1), tanhf(y) can be calculated as, |
| 3108 | + // tanhf(y) = -z / (z + 2.0) |
| 3109 | + // |
| 3110 | + // For other cases, call scalar tanhf() |
| 3111 | + // |
| 3112 | + // If x < 0, then we use the identity |
| 3113 | + // tanhf(-x) = -tanhf(x) |
| 3114 | + |
| 3115 | + private const uint SIGN_MASK = 0x7FFFFFFF; |
| 3116 | + |
| 3117 | + public static float Invoke(float x) => MathF.Tanh(x); |
| 3118 | + |
| 3119 | + public static Vector128<float> Invoke(Vector128<float> x) |
| 3120 | + { |
| 3121 | + Vector128<float> y = Vector128.Abs(x); |
| 3122 | + Vector128<float> z = ExpOperator.Invoke(Vector128.Create(-2f) * y) - Vector128.Create(1f); |
| 3123 | + Vector128<uint> sign = x.AsUInt32() & Vector128.Create(~SIGN_MASK); |
| 3124 | + return (sign ^ (-z / (z + Vector128.Create(2f))).AsUInt32()).AsSingle(); |
| 3125 | + } |
| 3126 | + |
| 3127 | + public static Vector256<float> Invoke(Vector256<float> x) |
| 3128 | + { |
| 3129 | + Vector256<float> y = Vector256.Abs(x); |
| 3130 | + Vector256<float> z = ExpOperator.Invoke(Vector256.Create(-2f) * y) - Vector256.Create(1f); |
| 3131 | + Vector256<uint> sign = x.AsUInt32() & Vector256.Create(~SIGN_MASK); |
| 3132 | + return (sign ^ (-z / (z + Vector256.Create(2f))).AsUInt32()).AsSingle(); |
| 3133 | + } |
| 3134 | + |
| 3135 | +#if NET8_0_OR_GREATER |
| 3136 | + public static Vector512<float> Invoke(Vector512<float> x) |
| 3137 | + { |
| 3138 | + Vector512<float> y = Vector512.Abs(x); |
| 3139 | + Vector512<float> z = ExpOperator.Invoke(Vector512.Create(-2f) * y) - Vector512.Create(1f); |
| 3140 | + Vector512<uint> sign = x.AsUInt32() & Vector512.Create(~SIGN_MASK); |
| 3141 | + return (sign ^ (-z / (z + Vector512.Create(2f))).AsUInt32()).AsSingle(); |
| 3142 | + } |
| 3143 | +#endif |
| 3144 | + } |
| 3145 | + |
2995 | 3146 | /// <summary>MathF.Log(x)</summary> |
2996 | 3147 | private readonly struct LogOperator : IUnaryOperator |
2997 | 3148 | { |
|
0 commit comments