From 8b770f17461a5859737e0f8f8f2800b06212e154 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Wed, 27 Sep 2023 21:41:28 -0400 Subject: [PATCH 1/3] Flesh out TensorPrimitives XML docs --- .../Numerics/Tensors/TensorPrimitives.cs | 911 +++++++++++++++--- .../Tensors/TensorPrimitives.netcore.cs | 10 + 2 files changed, 768 insertions(+), 153 deletions(-) diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.cs index 48ff55b4f0bd25..fdf8dadaa4ad36 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.cs @@ -6,72 +6,177 @@ namespace System.Numerics.Tensors /// Performs primitive tensor operations over spans of memory. public static partial class TensorPrimitives { - /// Computes the element-wise result of: MathF.Abs(). + /// Computes the element-wise absolute value of each single-precision floating-point number in the specified tensor. /// The tensor, represented as a span. /// The destination tensor, represented as a span. /// Destination is too short. - /// This method effectively does [i] = MathF.Abs([i]). + /// + /// + /// This method effectively computes [i] = MathF.Abs([i]). + /// + /// + /// The absolute value of a is its numeric value without its sign. For example, the absolute value of both 1.2e-03 and -1.2e03 is 1.2e03. + /// + /// + /// If a value is equal to or , the result stored into the corresponding destination location is set to . + /// If a value is equal to , the result stored into the corresponding destination location is set to . + /// + /// + /// and may not overlap; if they do, behavior is undefined. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void Abs(ReadOnlySpan x, Span destination) => InvokeSpanIntoSpan(x, destination); - /// Computes the element-wise result of: + . + /// Computes the element-wise addition of single-precision floating-point numbers in the specified tensors. /// The first tensor, represented as a span. /// The second tensor, represented as a span. /// The destination tensor, represented as a span. - /// Length of '' must be same as length of ''. + /// Length of must be same as length of . /// Destination is too short. - /// This method effectively does [i] = [i] + [i]. + /// + /// + /// This method effectively computes [i] = [i] + [i]. + /// + /// + /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. + /// + /// + /// If either of the element-wise input values is , the resulting element-wise value is . + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static unsafe void Add(ReadOnlySpan x, ReadOnlySpan y, Span destination) => InvokeSpanSpanIntoSpan(x, y, destination); - /// Computes the element-wise result of: + . + /// Computes the element-wise addition of single-precision floating-point numbers in the specified tensors. /// The first tensor, represented as a span. /// The second tensor, represented as a scalar. /// The destination tensor, represented as a span. /// Destination is too short. - /// This method effectively does [i] = [i] + . + /// + /// + /// This method effectively computes [i] = [i] + . + /// + /// + /// and may not overlap; if they do, behavior is undefined. + /// + /// + /// If either of the element-wise input values is , the resulting element-wise value is . + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void Add(ReadOnlySpan x, float y, Span destination) => InvokeSpanScalarIntoSpan(x, y, destination); - /// Computes the element-wise result of: ( + ) * . + /// Computes the element-wise result of ( + ) * for the specified tensors. /// The first tensor, represented as a span. /// The second tensor, represented as a span. /// The third tensor, represented as a span. /// The destination tensor, represented as a span. - /// Length of '' must be same as length of ''. - /// Length of '' must be same as length of ''. + /// Length of must be same as length of and the length of . /// Destination is too short. - /// This method effectively does [i] = ([i] + [i]) * [i]. + /// + /// + /// This method effectively computes [i] = ([i] + [i]) * [i]. + /// + /// + /// , , and may overlap, but none of them may overlap with ; if they do, behavior is undefined. + /// + /// + /// If any of the element-wise input values is , the resulting element-wise value is . + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void AddMultiply(ReadOnlySpan x, ReadOnlySpan y, ReadOnlySpan multiplier, Span destination) => InvokeSpanSpanSpanIntoSpan(x, y, multiplier, destination); - /// Computes the element-wise result of: ( + ) * . + /// Computes the element-wise result of ( + ) * for the specified tensors. /// The first tensor, represented as a span. /// The second tensor, represented as a span. /// The third tensor, represented as a scalar. /// The destination tensor, represented as a span. - /// Length of '' must be same as length of ''. + /// Length of must be same as length of . /// Destination is too short. - /// This method effectively does [i] = ([i] + [i]) * . + /// + /// + /// This method effectively computes [i] = ([i] + [i]) * . + /// + /// + /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. + /// + /// + /// If any of the element-wise input values is , the resulting element-wise value is . + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void AddMultiply(ReadOnlySpan x, ReadOnlySpan y, float multiplier, Span destination) => InvokeSpanSpanScalarIntoSpan(x, y, multiplier, destination); - /// Computes the element-wise result of: ( + ) * . + /// Computes the element-wise result of ( + ) * for the specified tensors. /// The first tensor, represented as a span. /// The second tensor, represented as a scalar. /// The third tensor, represented as a span. /// The destination tensor, represented as a span. - /// Length of '' must be same as length of ''. + /// Length of must be same as length of . /// Destination is too short. - /// This method effectively does [i] = ([i] + ) * [i]. + /// + /// + /// This method effectively computes [i] = ([i] + ) * [i]. + /// + /// + /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. + /// + /// + /// If any of the element-wise input values is , the resulting element-wise value is . + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void AddMultiply(ReadOnlySpan x, float y, ReadOnlySpan multiplier, Span destination) => InvokeSpanScalarSpanIntoSpan(x, y, multiplier, destination); - /// Computes the element-wise result of: cosh(). + /// Computes the element-wise hyperbolic cosine of each single-precision floating-point radian angle in the specified tensor. /// The tensor, represented as a span. /// The destination tensor, represented as a span. /// Destination is too short. - /// This method effectively does [i] = .Cosh([i]). + /// + /// + /// This method effectively computes [i] = .Cosh([i]). + /// + /// + /// and may not overlap; if they do, behavior is undefined. + /// + /// + /// If a value is equal to or , the result stored into the corresponding destination location is set to . + /// If a value is , the result stored into the corresponding destination location is set to . + /// + /// + /// The angles in x must be in radians. Multiply by /180 to convert degrees to radians. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void Cosh(ReadOnlySpan x, Span destination) { if (x.Length > destination.Length) @@ -85,12 +190,25 @@ public static void Cosh(ReadOnlySpan x, Span destination) } } - /// Computes the cosine similarity between two non-zero vectors. + /// Computes the cosine similarity between the two specified non-empty, equal-length tensors of single-precision floating-point numbers. /// The first tensor, represented as a span. /// The second tensor, represented as a span. - /// The cosine similarity between the two vectors. - /// Length of '' must be same as length of ''. - /// '' and '' must not be empty. + /// The cosine similarity of the two tensors. + /// Length of must be same as length of . + /// and must not be empty. + /// + /// + /// This method effectively computes TensorPrimitives.Dot(x, y) / (MathF.Sqrt(TensorPrimitives.SumOfSquares(x)) * MathF.Sqrt(TensorPrimitives.SumOfSquares(y)). + /// + /// + /// If any element in either input tensor is equal to , , or , + /// is returned. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static float CosineSimilarity(ReadOnlySpan x, ReadOnlySpan y) { if (x.IsEmpty) @@ -106,14 +224,30 @@ public static float CosineSimilarity(ReadOnlySpan x, ReadOnlySpan return CosineSimilarityCore(x, y); } - /// - /// Compute the distance between two points in Euclidean space. - /// + /// Computes the distance between two points, specified as non-empty, equal-length tensors of single-precision floating-point numbers, in Euclidean space. /// The first tensor, represented as a span. /// The second tensor, represented as a span. /// The Euclidean distance. - /// Length of '' must be same as length of ''. - /// '' and '' must not be empty. + /// Length of must be same as length of . + /// and must not be empty. + /// + /// + /// This method effectively computes the equivalent of: + /// + /// Span<float> difference = ...; + /// TensorPrimitives.Subtract(x, y, difference); + /// float result = MathF.Sqrt(TensorPrimitives.SumOfSquares(difference)); + /// + /// but without requiring additional temporary storage for the intermediate differences. + /// + /// + /// If any element in either input tensor is equal to , is returned. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static float Distance(ReadOnlySpan x, ReadOnlySpan y) { if (x.IsEmpty) @@ -129,33 +263,77 @@ public static float Distance(ReadOnlySpan x, ReadOnlySpan y) return MathF.Sqrt(Aggregate(0f, x, y)); } - /// Computes the element-wise result of: / . + /// Computes the element-wise division of single-precision floating-point numbers in the specified tensors. /// The first tensor, represented as a span. /// The second tensor, represented as a span. /// The destination tensor, represented as a span. - /// Length of '' must be same as length of ''. + /// Length of must be same as length of . /// Destination is too short. - /// This method effectively does [i] = [i] / . + /// + /// + /// This method effectively computes [i] = [i] / [i]. + /// + /// + /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. + /// + /// + /// If either of the element-wise input values is , the resulting element-wise value is . + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void Divide(ReadOnlySpan x, ReadOnlySpan y, Span destination) => InvokeSpanSpanIntoSpan(x, y, destination); - /// Computes the element-wise result of: / . + /// Computes the element-wise division of single-precision floating-point numbers in the specified tensors. /// The first tensor, represented as a span. /// The second tensor, represented as a scalar. /// The destination tensor, represented as a span. /// Destination is too short. - /// This method effectively does [i] = [i] / . + /// + /// + /// This method effectively computes [i] = [i] / . + /// + /// + /// and may not overlap; if they do, behavior is undefined. + /// + /// + /// If either of the element-wise input values is , the resulting element-wise value is . + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void Divide(ReadOnlySpan x, float y, Span destination) => InvokeSpanScalarIntoSpan(x, y, destination); - /// - /// A mathematical operation that takes two vectors and returns a scalar. - /// + /// Computes the dot product of two tensors containing single-precision floating-point numbers. /// The first tensor, represented as a span. /// The second tensor, represented as a span. /// The dot product. - /// Length of '' must be same as length of ''. - public static float Dot(ReadOnlySpan x, ReadOnlySpan y) // BLAS1: dot + /// Length of must be same as length of . + /// + /// + /// This method effectively computes the equivalent of: + /// + /// Span<float> products = ...; + /// TensorPrimitives.Multiply(x, y, products); + /// float result = TensorPrimitives.Sum(products); + /// + /// but without requiring additional temporary storage for the intermediate products. It corresponds to the dot method defined by BLAS1. + /// + /// + /// If any of the input elements is , the resulting value is . + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// + public static float Dot(ReadOnlySpan x, ReadOnlySpan y) { if (x.Length != y.Length) { @@ -165,11 +343,26 @@ public static float Dot(ReadOnlySpan x, ReadOnlySpan y) // BLAS1: return Aggregate(0f, x, y); } - /// Computes the element-wise result of: pow(e, ). + /// Computes the element-wise result of raising e to the single-precision floating-point number powers in the specified tensor. /// The tensor, represented as a span. /// The destination tensor, represented as a span. /// Destination is too short. - /// This method effectively does [i] = .Exp([i]). + /// + /// + /// This method effectively computes [i] = .Exp([i]). + /// + /// + /// and may not overlap; if they do, behavior is undefined. + /// + /// + /// If a value equals or , the result stored into the corresponding destination location is set to . + /// If a value equals , the result stored into the corresponding destination location is set to 0. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void Exp(ReadOnlySpan x, Span destination) { if (x.Length > destination.Length) @@ -183,9 +376,19 @@ public static void Exp(ReadOnlySpan x, Span destination) } } - /// Computes the index of the maximum element in . + /// Searches for the index of the largest single-precision floating-point number in the specified tensor. /// The tensor, represented as a span. /// The index of the maximum element in , or -1 if is empty. + /// + /// + /// The determination of the maximum element matches the IEEE 754:2019 `maximum` function. If any + /// value is present, the index of the first is returned. Positive 0 is considered greater than negative 0. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static unsafe int IndexOfMax(ReadOnlySpan x) { int result = -1; @@ -196,11 +399,6 @@ public static unsafe int IndexOfMax(ReadOnlySpan x) for (int i = 0; i < x.Length; i++) { - // This matches the IEEE 754:2019 `maximum` function. - // It propagates NaN inputs back to the caller and - // otherwise returns the greater of the inputs. - // It treats +0 as greater than -0 as per the specification. - float current = x[i]; if (current != max) @@ -227,10 +425,20 @@ public static unsafe int IndexOfMax(ReadOnlySpan x) return result; } - /// Computes the index of the element in with the maximum magnitude. + /// Searches for the index of the single-precision floating-point number with the largest magnitude in the specified tensor. /// The tensor, represented as a span. - /// The index of the element with the maximum magnitude, or -1 if is empty. - /// This method corresponds to the iamax method defined by BLAS1. + /// The index of the element in with the largest magnitude (absolute value), or -1 if is empty. + /// + /// + /// The determination of the maximum magnitude matches the IEEE 754:2019 `maximumMagnitude` function. If any + /// value is present, the index of the first is returned. If two values have the same magnitude and one is positive and the other is negative, + /// the positive value is considered to have the larger magnitude. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static unsafe int IndexOfMaxMagnitude(ReadOnlySpan x) { int result = -1; @@ -242,11 +450,6 @@ public static unsafe int IndexOfMaxMagnitude(ReadOnlySpan x) for (int i = 0; i < x.Length; i++) { - // This matches the IEEE 754:2019 `maximumMagnitude` function. - // It propagates NaN inputs back to the caller and - // otherwise returns the input with a greater magnitude. - // It treats +0 as greater than -0 as per the specification. - float current = x[i]; float currentMag = Math.Abs(current); @@ -276,9 +479,19 @@ public static unsafe int IndexOfMaxMagnitude(ReadOnlySpan x) return result; } - /// Computes the index of the minimum element in . + /// Searches for the index of the smallest single-precision floating-point number in the specified tensor. /// The tensor, represented as a span. /// The index of the minimum element in , or -1 if is empty. + /// + /// + /// The determination of the minimum element matches the IEEE 754:2019 `minimum` function. If any + /// value is present, the index of the first is returned. Negative 0 is considered smaller than positive 0. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static unsafe int IndexOfMin(ReadOnlySpan x) { int result = -1; @@ -289,11 +502,6 @@ public static unsafe int IndexOfMin(ReadOnlySpan x) for (int i = 0; i < x.Length; i++) { - // This matches the IEEE 754:2019 `minimum` function. - // It propagates NaN inputs back to the caller and - // otherwise returns the lesser of the inputs. - // It treats +0 as greater than -0 as per the specification. - float current = x[i]; if (current != min) @@ -320,9 +528,20 @@ public static unsafe int IndexOfMin(ReadOnlySpan x) return result; } - /// Computes the index of the element in with the minimum magnitude. + /// Searches for the index of the single-precision floating-point number with the smallest magnitude in the specified tensor. /// The tensor, represented as a span. - /// The index of the element with the minimum magnitude, or -1 if is empty. + /// The index of the element in with the smallest magnitude (absolute value), or -1 if is empty. + /// + /// + /// The determination of the minimum magnitude matches the IEEE 754:2019 `minimumMagnitude` function. If any + /// value is present, the index of the first is returned. If two values have the same magnitude and one is positive and the other is negative, + /// the negative value is considered to have the smaller magnitude. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static unsafe int IndexOfMinMagnitude(ReadOnlySpan x) { int result = -1; @@ -334,11 +553,6 @@ public static unsafe int IndexOfMinMagnitude(ReadOnlySpan x) for (int i = 0; i < x.Length; i++) { - // This matches the IEEE 754:2019 `minimumMagnitude` function - // It propagates NaN inputs back to the caller and - // otherwise returns the input with a lesser magnitude. - // It treats +0 as greater than -0 as per the specification. - float current = x[i]; float currentMag = Math.Abs(current); @@ -368,11 +582,28 @@ public static unsafe int IndexOfMinMagnitude(ReadOnlySpan x) return result; } - /// Computes the element-wise result of: ln(). + /// Computes the element-wise natural (base e) logarithm of single-precision floating-point numbers in the specified tensor. /// The tensor, represented as a span. /// The destination tensor, represented as a span. /// Destination is too short. - /// This method effectively does [i] = .Log([i]). + /// + /// + /// This method effectively computes [i] = .Log([i]). + /// + /// + /// and may not overlap; if they do, behavior is undefined. + /// + /// + /// If a value equals 0, the result stored into the corresponding destination location is set to . + /// If a value is negative or NaN, the result stored into the corresponding destination location is set to . + /// If a value is positive infinity, the result stored into the corresponding destination location is set to . + /// Otherwise, if a value is positive, its natural logarithm is stored into the corresponding destination location. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void Log(ReadOnlySpan x, Span destination) { if (x.Length > destination.Length) @@ -386,11 +617,28 @@ public static void Log(ReadOnlySpan x, Span destination) } } - /// Computes the element-wise result of: log2(). + /// Computes the element-wise base 2 logarithm of single-precision floating-point numbers in the specified tensor. /// The tensor, represented as a span. /// The destination tensor, represented as a span. /// Destination is too short. - /// This method effectively does [i] = .Log2([i]). + /// + /// + /// This method effectively computes [i] = .Log2([i]). + /// + /// + /// and may not overlap; if they do, behavior is undefined. + /// + /// + /// If a value equals 0, the result stored into the corresponding destination location is set to . + /// If a value is negative or NaN, the result stored into the corresponding destination location is set to . + /// If a value is positive infinity, the result stored into the corresponding destination location is set to . + /// Otherwise, if a value is positive, its natural logarithm is stored into the corresponding destination location. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void Log2(ReadOnlySpan x, Span destination) { if (x.Length > destination.Length) @@ -404,153 +652,362 @@ public static void Log2(ReadOnlySpan x, Span destination) } } - /// Computes the maximum element in . + /// Searches for the largest single-precision floating-point number in the specified tensor. /// The tensor, represented as a span. /// The maximum element in . - /// Length of '' must be greater than zero. + /// Length of must be greater than zero. + /// + /// + /// The determination of the maximum element matches the IEEE 754:2019 `maximum` function. If any + /// value is present, the first is returned. Positive 0 is considered greater than negative 0. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static float Max(ReadOnlySpan x) => MinMaxCore(x); - /// Computes the element-wise result of: MathF.Max(, ). + /// Computes the element-wise maximum of the single-precision floating-point numbers in the specified tensors. /// The first tensor, represented as a span. /// The second tensor, represented as a span. /// The destination tensor, represented as a span. - /// Length of '' must be same as length of ''. + /// Length of must be same as length of . /// Destination is too short. - /// This method effectively does [i] = MathF.Max([i], [i]). + /// + /// + /// This method effectively computes [i] = MathF.Max([i], [i]). + /// + /// + /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. + /// + /// + /// The determination of the maximum element matches the IEEE 754:2019 `maximum` function. If either value is , + /// that value is stored as the result. Positive 0 is considered greater than negative 0. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void Max(ReadOnlySpan x, ReadOnlySpan y, Span destination) => InvokeSpanSpanIntoSpan(x, y, destination); - /// Computes the maximum magnitude of any element in . + /// Searches for the single-precision floating-point number with the largest magnitude in the specified tensor. /// The tensor, represented as a span. - /// The maximum magnitude of any element in . - /// Length of '' must be greater than zero. + /// The element in with the largest magnitude (absolute value). + /// Length of must be greater than zero. + /// + /// + /// The determination of the maximum magnitude matches the IEEE 754:2019 `maximumMagnitude` function. If any + /// value is present, the first is returned. If two values have the same magnitude and one is positive and the other is negative, + /// the positive value is considered to have the larger magnitude. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static float MaxMagnitude(ReadOnlySpan x) => MinMaxCore(x); - /// Computes the element-wise result of: MathF.MaxMagnitude(, ). + /// Computes the element-wise single-precision floating-point number with the largest magnitude in the specified tensors. /// The first tensor, represented as a span. /// The second tensor, represented as a span. /// The destination tensor, represented as a span. - /// Length of '' must be same as length of ''. + /// Length of must be same as length of . /// Destination is too short. - /// This method effectively does [i] = MathF.MaxMagnitude([i], [i]). + /// This method effectively computes [i] = MathF.MaxMagnitude([i], [i]). + /// + /// + /// The determination of the maximum magnitude matches the IEEE 754:2019 `maximumMagnitude` function. If either value is , + /// that value is stored as the result. If the two values have the same magnitude and one is positive and the other is negative, + /// the positive value is considered to have the larger magnitude. + /// + /// + /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void MaxMagnitude(ReadOnlySpan x, ReadOnlySpan y, Span destination) => InvokeSpanSpanIntoSpan(x, y, destination); - /// Computes the minimum element in . + /// Searches for the smallest single-precision floating-point number in the specified tensor. /// The tensor, represented as a span. /// The minimum element in . - /// Length of '' must be greater than zero. + /// Length of must be greater than zero. + /// + /// + /// The determination of the minimum element matches the IEEE 754:2019 `minimum` function. If any + /// value is present, the first is returned. Negative 0 is considered smaller than positive 0. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static float Min(ReadOnlySpan x) => MinMaxCore(x); - /// Computes the element-wise result of: MathF.Min(, ). + /// Computes the element-wise minimum of the single-precision floating-point numbers in the specified tensors. /// The first tensor, represented as a span. /// The second tensor, represented as a span. /// The destination tensor, represented as a span. - /// Length of '' must be same as length of ''. + /// Length of must be same as length of . /// Destination is too short. - /// This method effectively does [i] = MathF.Min([i], [i]). + /// + /// + /// This method effectively computes [i] = MathF.Max([i], [i]). + /// + /// + /// The determination of the maximum element matches the IEEE 754:2019 `maximum` function. If either value is , + /// that value is stored as the result. Positive 0 is considered greater than negative 0. + /// + /// + /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void Min(ReadOnlySpan x, ReadOnlySpan y, Span destination) => InvokeSpanSpanIntoSpan(x, y, destination); - /// Computes the minimum magnitude of any element in . + /// Searches for the single-precision floating-point number with the smallest magnitude in the specified tensor. /// The tensor, represented as a span. - /// The minimum magnitude of any element in . - /// Length of '' must be greater than zero. + /// The element in with the smallest magnitude (absolute value). + /// Length of must be greater than zero. + /// + /// + /// The determination of the minimum magnitude matches the IEEE 754:2019 `minimumMagnitude` function. If any + /// value is present, the first is returned. If two values have the same magnitude and one is positive and the other is negative, + /// the negative value is considered to have the smaller magnitude. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static float MinMagnitude(ReadOnlySpan x) => MinMaxCore(x); - /// Computes the element-wise result of: MathF.MinMagnitude(, ). + /// Computes the element-wise single-precision floating-point number with the smallest magnitude in the specified tensors. /// The first tensor, represented as a span. /// The second tensor, represented as a span. /// The destination tensor, represented as a span. - /// Length of '' must be same as length of ''. + /// Length of must be same as length of . /// Destination is too short. - /// This method effectively does [i] = MathF.MinMagnitude([i], [i]). + /// This method effectively computes [i] = MathF.MinMagnitude([i], [i]). + /// + /// + /// The determination of the maximum magnitude matches the IEEE 754:2019 `minimumMagnitude` function. If either value is , + /// that value is stored as the result. If the two values have the same magnitude and one is positive and the other is negative, + /// the negative value is considered to have the smaller magnitude. + /// + /// + /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void MinMagnitude(ReadOnlySpan x, ReadOnlySpan y, Span destination) => InvokeSpanSpanIntoSpan(x, y, destination); - /// Computes the element-wise result of: * . + /// Computes the element-wise product of single-precision floating-point numbers in the specified tensors. /// The first tensor, represented as a span. /// The second tensor, represented as a span. /// The destination tensor, represented as a span. - /// Length of '' must be same as length of ''. + /// Length of must be same as length of . /// Destination is too short. - /// This method effectively does [i] = [i] * . + /// + /// + /// This method effectively computes [i] = [i] * [i]. + /// + /// + /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. + /// + /// + /// If either of the element-wise input values is , the resulting element-wise value is . + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void Multiply(ReadOnlySpan x, ReadOnlySpan y, Span destination) => InvokeSpanSpanIntoSpan(x, y, destination); - /// Computes the element-wise result of: * . + /// Computes the element-wise product of single-precision floating-point numbers in the specified tensors. /// The first tensor, represented as a span. /// The second tensor, represented as a scalar. /// The destination tensor, represented as a span. /// Destination is too short. /// - /// This method effectively does [i] = [i] * . - /// This method corresponds to the scal method defined by BLAS1. + /// + /// This method effectively computes [i] = [i] * . + /// It corresponds to the scal method defined by BLAS1. + /// + /// + /// and may not overlap; if they do, behavior is undefined. + /// + /// + /// If either of the element-wise input values is , the resulting element-wise value is . + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// /// public static void Multiply(ReadOnlySpan x, float y, Span destination) => InvokeSpanScalarIntoSpan(x, y, destination); - /// Computes the element-wise result of: ( * ) + . + /// Computes the element-wise result of ( * ) * for the specified tensors of single-precision floating-point numbers. /// The first tensor, represented as a span. /// The second tensor, represented as a span. /// The third tensor, represented as a span. /// The destination tensor, represented as a span. - /// Length of '' must be same as length of ''. - /// Length of '' must be same as length of ''. + /// Length of must be same as length of and length of . /// Destination is too short. - /// This method effectively does [i] = ([i] * [i]) + [i]. + /// + /// + /// This method effectively computes [i] = ([i] * [i]) + [i]. + /// + /// + /// , , and may overlap, but none of them may overlap with ; if they do, behavior is undefined. + /// + /// + /// If any of the element-wise input values is , the resulting element-wise value is . + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. On some platforms, this may perform the operation rounded as one ternary operation, such that it computes ( * ) + /// as if to infinite precision, adds to that result as if to infinite precision, and finally rounds to the nearest representable value. On architectures where such + /// a fused multiply-add is not supported, this will compute ( * ) as if to infinite precision, round the result to the nearest representable value, + /// add to the rounded result as if to infinite precision, and finally round to the nearest representable value. + /// + /// public static void MultiplyAdd(ReadOnlySpan x, ReadOnlySpan y, ReadOnlySpan addend, Span destination) => InvokeSpanSpanSpanIntoSpan(x, y, addend, destination); - /// Computes the element-wise result of: ( * ) + . + /// Computes the element-wise result of ( * ) * for the specified tensors of single-precision floating-point numbers. /// The first tensor, represented as a span. /// The second tensor, represented as a span. - /// The third tensor, represented as a span. + /// The third tensor, represented as a scalar. /// The destination tensor, represented as a span. - /// Length of '' must be same as length of ''. + /// Length of must be same as length of . /// Destination is too short. /// - /// This method effectively does [i] = ([i] * [i]) + . - /// This method corresponds to the axpy method defined by BLAS1. + /// + /// This method effectively computes [i] = ([i] * [i]) + . + /// It corresponds to the axpy method defined by BLAS1. + /// + /// + /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. + /// + /// + /// If any of the element-wise input values is , the resulting element-wise value is . + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. On some platforms, this may perform the operation rounded as one ternary operation, such that it computes ( * ) + /// as if to infinite precision, adds to that result as if to infinite precision, and finally rounds to the nearest representable value. On architectures where such + /// a fused multiply-add is not supported, this will compute ( * ) as if to infinite precision, round the result to the nearest representable value, + /// add to the rounded result as if to infinite precision, and finally round to the nearest representable value. + /// /// public static void MultiplyAdd(ReadOnlySpan x, ReadOnlySpan y, float addend, Span destination) => InvokeSpanSpanScalarIntoSpan(x, y, addend, destination); - /// Computes the element-wise result of: ( * ) + . + /// Computes the element-wise result of ( * ) * for the specified tensors of single-precision floating-point numbers. /// The first tensor, represented as a span. - /// The second tensor, represented as a span. + /// The second tensor, represented as a scalar. /// The third tensor, represented as a span. /// The destination tensor, represented as a span. - /// Length of '' must be same as length of ''. + /// Length of must be same as length of . /// Destination is too short. - /// This method effectively does [i] = ([i] * ) + [i]. + /// + /// + /// This method effectively computes [i] = ([i] * ) + [i]. + /// + /// + /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. + /// + /// + /// If any of the element-wise input values is , the resulting element-wise value is . + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. On some platforms, this may perform the operation rounded as one ternary operation, such that it computes ( * ) + /// as if to infinite precision, adds to that result as if to infinite precision, and finally rounds to the nearest representable value. On architectures where such + /// a fused multiply-add is not supported, this will compute ( * ) as if to infinite precision, round the result to the nearest representable value, + /// add to the rounded result as if to infinite precision, and finally round to the nearest representable value. + /// + /// public static void MultiplyAdd(ReadOnlySpan x, float y, ReadOnlySpan addend, Span destination) => InvokeSpanScalarSpanIntoSpan(x, y, addend, destination); - /// Computes the element-wise result of: -. + /// Computes the element-wise negation of each single-precision floating-point number in the specified tensor. /// The tensor, represented as a span. /// The destination tensor, represented as a span. /// Destination is too short. - /// This method effectively does [i] = -[i]. + /// + /// + /// This method effectively computes [i] = -[i]. + /// + /// + /// and may not overlap; if they do, behavior is undefined. + /// + /// + /// If any of the element-wise input values is , the resulting element-wise value is . + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void Negate(ReadOnlySpan x, Span destination) => InvokeSpanIntoSpan(x, destination); - /// - /// A mathematical operation that takes a vector and returns the L2 norm. - /// + /// Computes the Euclidean norm of the specified tensor of single-precision floating-point numbers. /// The first tensor, represented as a span. - /// The L2 norm. - public static float Norm(ReadOnlySpan x) => // BLAS1: nrm2 - MathF.Sqrt(Aggregate(0f, x)); + /// The norm. + /// + /// + /// This method effectively computes MathF.Sqrt(TensorPrimitives.SumOfSquares(x)). + /// This is often referred to as the Euclidean norm or L2 norm. + /// It corresponds to the nrm2 method defined by BLAS1. + /// + /// + /// If any of the input values is , the result value is . + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// + public static float Norm(ReadOnlySpan x) => + MathF.Sqrt(SumOfSquares(x)); - /// Computes the product of all elements in . + /// Computes the product of all elements in the specified non-empty tensor of single-precision floating-point numbers. /// The tensor, represented as a span. /// The result of multiplying all elements in . - /// Length of '' must be greater than zero. + /// Length of must be greater than zero. + /// + /// + /// If any of the input values is , the result value is . + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static float Product(ReadOnlySpan x) { if (x.IsEmpty) @@ -561,13 +1018,27 @@ public static float Product(ReadOnlySpan x) return Aggregate(1.0f, x); } - /// Computes the product of the element-wise result of: - . + /// Computes the product of the element-wise differences of the single-precision floating-point numbers in the specified non-empty tensors. /// The first tensor, represented as a span. /// The second tensor, represented as a span. /// The result of multiplying the element-wise subtraction of the elements in the second tensor from the first tensor. /// Length of both input spans must be greater than zero. /// and must have the same length. - /// This method effectively does .Product(.Subtract(, )). + /// + /// + /// This method effectively computes: + /// + /// Span<float> differences = ...; + /// TensorPrimitives.Subtract(x, y, differences); + /// float result = TensorPrimitives.Product(differences); + /// + /// but without requiring additional temporary storage for the intermediate differences. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static float ProductOfDifferences(ReadOnlySpan x, ReadOnlySpan y) { if (x.IsEmpty) @@ -583,13 +1054,27 @@ public static float ProductOfDifferences(ReadOnlySpan x, ReadOnlySpan(1.0f, x, y); } - /// Computes the product of the element-wise result of: + . + /// Computes the product of the element-wise sums of the single-precision floating-point numbers in the specified non-empty tensors. /// The first tensor, represented as a span. /// The second tensor, represented as a span. /// The result of multiplying the element-wise additions of the elements in each tensor. /// Length of both input spans must be greater than zero. /// and must have the same length. - /// This method effectively does .Product(.Add(, )). + /// + /// + /// This method effectively computes: + /// + /// Span<float> sums = ...; + /// TensorPrimitives.Add(x, y, sums); + /// float result = TensorPrimitives.Product(sums); + /// + /// but without requiring additional temporary storage for the intermediate sums. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static float ProductOfSums(ReadOnlySpan x, ReadOnlySpan y) { if (x.IsEmpty) @@ -605,13 +1090,23 @@ public static float ProductOfSums(ReadOnlySpan x, ReadOnlySpan y) return Aggregate(1.0f, x, y); } - /// - /// A function that takes a real number and returns a value between 0 and 1. - /// - /// The first tensor, represented as a span. + /// Computes the element-wise sigmoid function on the specified non-empty tensor of single-precision floating-point numbers. + /// The tensor, represented as a span. /// The destination tensor. /// Destination is too short. - /// '' must not be empty. + /// must not be empty. + /// + /// + /// This method effectively computes [i] = 1f / (1f + .Exp(-[i])). + /// + /// + /// and may not overlap; if they do, behavior is undefined. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void Sigmoid(ReadOnlySpan x, Span destination) { if (x.IsEmpty) @@ -626,15 +1121,33 @@ public static void Sigmoid(ReadOnlySpan x, Span destination) for (int i = 0; i < x.Length; i++) { - destination[i] = 1f / (1 + MathF.Exp(-x[i])); + destination[i] = 1f / (1f + MathF.Exp(-x[i])); } } - /// Computes the element-wise result of: sinh(). + /// Computes the element-wise hyperbolic sine of each single-precision floating-point radian angle in the specified tensor. /// The tensor, represented as a span. /// The destination tensor, represented as a span. /// Destination is too short. - /// This method effectively does [i] = .Sinh([i]). + /// + /// + /// This method effectively computes [i] = .Sinh([i]). + /// + /// + /// and may not overlap; if they do, behavior is undefined. + /// + /// + /// If a value is equal to , , or , + /// the corresponding destination location is set to that value. + /// + /// + /// The angles in x must be in radians. Multiply by /180 to convert degrees to radians. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void Sinh(ReadOnlySpan x, Span destination) { if (x.Length > destination.Length) @@ -648,13 +1161,24 @@ public static void Sinh(ReadOnlySpan x, Span destination) } } - /// - /// A function that takes a collection of real numbers and returns a probability distribution. - /// - /// The first tensor, represented as a span. + /// Computes the softmax function over the specified non-empty tensor of single-precision floating-point numbers. + /// The tensor, represented as a span. /// The destination tensor. /// Destination is too short. - /// '' must not be empty. + /// must not be empty. + /// + /// + /// This method effectively computes a sum of MathF.Exp(x[i]) for all elements in . + /// It then effectively computes [i] = MathF.Exp([i]) / sum. + /// + /// + /// and may not overlap; if they do, behavior is undefined. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void SoftMax(ReadOnlySpan x, Span destination) { if (x.IsEmpty) @@ -680,53 +1204,134 @@ public static void SoftMax(ReadOnlySpan x, Span destination) } } - /// Computes the element-wise result of: - . + /// Computes the element-wise difference between single-precision floating-point numbers in the specified tensors. /// The first tensor, represented as a span. /// The second tensor, represented as a scalar. /// The destination tensor, represented as a span. - /// Length of '' must be same as length of ''. + /// Length of must be same as length of . /// Destination is too short. - /// This method effectively does [i] = [i] - [i]. + /// + /// + /// This method effectively computes [i] = [i] - [i]. + /// + /// + /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. + /// + /// + /// If either of the element-wise input values is , the resulting element-wise value is . + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void Subtract(ReadOnlySpan x, ReadOnlySpan y, Span destination) => InvokeSpanSpanIntoSpan(x, y, destination); - /// Computes the element-wise result of: - . + /// Computes the element-wise difference between single-precision floating-point numbers in the specified tensors. /// The first tensor, represented as a span. /// The second tensor, represented as a scalar. /// The destination tensor, represented as a span. /// Destination is too short. - /// This method effectively does [i] = [i] - . + /// + /// + /// This method effectively computes [i] = [i] - . + /// + /// + /// and may not overlap; if they do, behavior is undefined. + /// + /// + /// If either of the element-wise input values is , the resulting element-wise value is . + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void Subtract(ReadOnlySpan x, float y, Span destination) => InvokeSpanScalarIntoSpan(x, y, destination); - /// Computes the sum of all elements in . + /// Computes the sum of all elements in the specified tensor of single-precision floating-point numbers. /// The tensor, represented as a span. /// The result of adding all elements in , or zero if is empty. + /// + /// + /// If any of the values in the input is , the result is . + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static float Sum(ReadOnlySpan x) => Aggregate(0f, x); - /// Computes the sum of the absolute values of every element in . + /// Computes the sum of the absolute values of every element in the specified tensor of single-precision floating-point numbers. /// The tensor, represented as a span. /// The result of adding the absolute value of every element in , or zero if is empty. /// - /// This method effectively does .Sum(.Abs()). - /// This method corresponds to the asum method defined by BLAS1. + /// + /// This method effectively computes: + /// + /// Span<float> absoluteValues = ...; + /// TensorPrimitives.Abs(x, absoluteValues); + /// float result = TensorPrimitives.Sum(absoluteValues); + /// + /// but without requiring intermediate storage for the absolute values. It corresponds to the asum method defined by BLAS1. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// /// public static float SumOfMagnitudes(ReadOnlySpan x) => Aggregate(0f, x); - /// Computes the sum of the squares of every element in . + /// Computes the sum of the square of every element in the specified tensor of single-precision floating-point numbers. /// The tensor, represented as a span. - /// The result of adding every element in multiplied by itself, or zero if is empty. - /// This method effectively does .Sum(.Multiply(, )). + /// The result of adding the square of every element in , or zero if is empty. + /// + /// + /// This method effectively computes: + /// + /// Span<float> squaredValues = ...; + /// TensorPrimitives.Multiply(x, x, squaredValues); + /// float result = TensorPrimitives.Sum(squaredValues); + /// + /// but without requiring intermediate storage for the squared values. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static float SumOfSquares(ReadOnlySpan x) => Aggregate(0f, x); - /// Computes the element-wise result of: tanh(). + /// Computes the element-wise hyperbolic tangent of each single-precision floating-point radian angle in the specified tensor. /// The tensor, represented as a span. /// The destination tensor, represented as a span. /// Destination is too short. - /// This method effectively does [i] = .Tanh([i]). + /// + /// + /// This method effectively computes [i] = .Tanh([i]). + /// + /// + /// and may not overlap; if they do, behavior is undefined. + /// + /// + /// If a value is equal to , the corresponding destination location is set to -1. + /// If a value is equal to , the corresponding destination location is set to 1. + /// If a value is , the corresponding destination location is set to . + /// + /// + /// The angles in x must be in radians. Multiply by /180 to convert degrees to radians. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// public static void Tanh(ReadOnlySpan x, Span destination) { if (x.Length > destination.Length) diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netcore.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netcore.cs index e82f67b1f27d51..ec62ca0d670de7 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netcore.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netcore.cs @@ -19,6 +19,11 @@ public static partial class TensorPrimitives /// The source span from which to copy values. /// The destination span into which the converted values should be written. /// Destination is too short. + /// + /// + /// This method effectively computes [i] = (Half)[i]. + /// + /// public static void ConvertToHalf(ReadOnlySpan source, Span destination) { if (source.Length > destination.Length) @@ -39,6 +44,11 @@ public static void ConvertToHalf(ReadOnlySpan source, Span destinat /// The source span from which to copy values. /// The destination span into which the converted values should be written. /// Destination is too short. + /// + /// + /// This method effectively computes [i] = (float)[i]. + /// + /// public static void ConvertToSingle(ReadOnlySpan source, Span destination) { if (source.Length > destination.Length) From 40f1cf425e9e309bf8e8f647c0cfd07eddb9fa03 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Thu, 28 Sep 2023 15:26:45 -0400 Subject: [PATCH 2/3] Address PR feedback - Remove use of FusedMultiplyAdd from all but CosineSimilarity - Remove comments about platform/OS-specific behavior from Add/AddMultiply/Subtract/Multiply/MultiplyAdd/Divide/Negate - Loosen comments about NaN and which exact one is returned --- .../Numerics/Tensors/TensorPrimitives.cs | 167 +++++------------- .../Tensors/TensorPrimitives.netcore.cs | 8 +- 2 files changed, 51 insertions(+), 124 deletions(-) diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.cs index 35bd6f334dfbd6..807dd2edadd99a 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.cs @@ -19,15 +19,11 @@ public static partial class TensorPrimitives /// /// /// If a value is equal to or , the result stored into the corresponding destination location is set to . - /// If a value is equal to , the result stored into the corresponding destination location is set to . + /// If a value is equal to , the result stored into the corresponding destination location is the original NaN value with the sign bit removed. /// /// /// and may not overlap; if they do, behavior is undefined. /// - /// - /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different - /// operating systems or architectures. - /// /// public static void Abs(ReadOnlySpan x, Span destination) => InvokeSpanIntoSpan(x, destination); @@ -46,11 +42,7 @@ public static void Abs(ReadOnlySpan x, Span destination) => /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. /// /// - /// If either of the element-wise input values is , the resulting element-wise value is . - /// - /// - /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different - /// operating systems or architectures. + /// If either of the element-wise input values is equal to , the resulting element-wise value is also NaN. /// /// public static unsafe void Add(ReadOnlySpan x, ReadOnlySpan y, Span destination) => @@ -69,11 +61,7 @@ public static unsafe void Add(ReadOnlySpan x, ReadOnlySpan y, Span /// and may not overlap; if they do, behavior is undefined. /// /// - /// If either of the element-wise input values is , the resulting element-wise value is . - /// - /// - /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different - /// operating systems or architectures. + /// If either of the element-wise input values is equal to , the resulting element-wise value is also NaN. /// /// public static void Add(ReadOnlySpan x, float y, Span destination) => @@ -94,11 +82,7 @@ public static void Add(ReadOnlySpan x, float y, Span destination) /// , , and may overlap, but none of them may overlap with ; if they do, behavior is undefined. /// /// - /// If any of the element-wise input values is , the resulting element-wise value is . - /// - /// - /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different - /// operating systems or architectures. + /// If any of the element-wise input values is equal to , the resulting element-wise value is also NaN. /// /// public static void AddMultiply(ReadOnlySpan x, ReadOnlySpan y, ReadOnlySpan multiplier, Span destination) => @@ -119,11 +103,7 @@ public static void AddMultiply(ReadOnlySpan x, ReadOnlySpan y, Rea /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. /// /// - /// If any of the element-wise input values is , the resulting element-wise value is . - /// - /// - /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different - /// operating systems or architectures. + /// If any of the element-wise input values is equal to , the resulting element-wise value is also NaN. /// /// public static void AddMultiply(ReadOnlySpan x, ReadOnlySpan y, float multiplier, Span destination) => @@ -144,11 +124,7 @@ public static void AddMultiply(ReadOnlySpan x, ReadOnlySpan y, flo /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. /// /// - /// If any of the element-wise input values is , the resulting element-wise value is . - /// - /// - /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different - /// operating systems or architectures. + /// If any of the element-wise input values is equal to , the resulting element-wise value is also NaN. /// /// public static void AddMultiply(ReadOnlySpan x, float y, ReadOnlySpan multiplier, Span destination) => @@ -167,7 +143,7 @@ public static void AddMultiply(ReadOnlySpan x, float y, ReadOnlySpan /// /// If a value is equal to or , the result stored into the corresponding destination location is set to . - /// If a value is , the result stored into the corresponding destination location is set to . + /// If a value is equal to , the result stored into the corresponding destination location is also NaN. /// /// /// The angles in x must be in radians. Multiply by /180 to convert degrees to radians. @@ -202,7 +178,7 @@ public static void Cosh(ReadOnlySpan x, Span destination) /// /// /// If any element in either input tensor is equal to , , or , - /// is returned. + /// NaN is returned. /// /// /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different @@ -241,7 +217,7 @@ public static float CosineSimilarity(ReadOnlySpan x, ReadOnlySpan /// but without requiring additional temporary storage for the intermediate differences. /// /// - /// If any element in either input tensor is equal to , is returned. + /// If any element in either input tensor is equal to , NaN is returned. /// /// /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different @@ -277,11 +253,7 @@ public static float Distance(ReadOnlySpan x, ReadOnlySpan y) /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. /// /// - /// If either of the element-wise input values is , the resulting element-wise value is . - /// - /// - /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different - /// operating systems or architectures. + /// If either of the element-wise input values is equal to , the resulting element-wise value is also NaN. /// /// public static void Divide(ReadOnlySpan x, ReadOnlySpan y, Span destination) => @@ -300,11 +272,7 @@ public static void Divide(ReadOnlySpan x, ReadOnlySpan y, Span and may not overlap; if they do, behavior is undefined. /// /// - /// If either of the element-wise input values is , the resulting element-wise value is . - /// - /// - /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different - /// operating systems or architectures. + /// If either of the element-wise input values is equal to , the resulting element-wise value is also NaN. /// /// public static void Divide(ReadOnlySpan x, float y, Span destination) => @@ -326,7 +294,7 @@ public static void Divide(ReadOnlySpan x, float y, Span destinatio /// but without requiring additional temporary storage for the intermediate products. It corresponds to the dot method defined by BLAS1. /// /// - /// If any of the input elements is , the resulting value is . + /// If any of the input elements is equal to , the resulting value is also NaN. /// /// /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different @@ -355,7 +323,7 @@ public static float Dot(ReadOnlySpan x, ReadOnlySpan y) /// and may not overlap; if they do, behavior is undefined. /// /// - /// If a value equals or , the result stored into the corresponding destination location is set to . + /// If a value equals or , the result stored into the corresponding destination location is set to NaN. /// If a value equals , the result stored into the corresponding destination location is set to 0. /// /// @@ -381,8 +349,8 @@ public static void Exp(ReadOnlySpan x, Span destination) /// The index of the maximum element in , or -1 if is empty. /// /// - /// The determination of the maximum element matches the IEEE 754:2019 `maximum` function. If any - /// value is present, the index of the first is returned. Positive 0 is considered greater than negative 0. + /// The determination of the maximum element matches the IEEE 754:2019 `maximum` function. If any value equal to + /// is present, the index of the first is returned. Positive 0 is considered greater than negative 0. /// /// /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different @@ -430,8 +398,8 @@ public static unsafe int IndexOfMax(ReadOnlySpan x) /// The index of the element in with the largest magnitude (absolute value), or -1 if is empty. /// /// - /// The determination of the maximum magnitude matches the IEEE 754:2019 `maximumMagnitude` function. If any - /// value is present, the index of the first is returned. If two values have the same magnitude and one is positive and the other is negative, + /// The determination of the maximum magnitude matches the IEEE 754:2019 `maximumMagnitude` function. If any value equal to + /// is present, the index of the first is returned. If two values have the same magnitude and one is positive and the other is negative, /// the positive value is considered to have the larger magnitude. /// /// @@ -484,8 +452,8 @@ public static unsafe int IndexOfMaxMagnitude(ReadOnlySpan x) /// The index of the minimum element in , or -1 if is empty. /// /// - /// The determination of the minimum element matches the IEEE 754:2019 `minimum` function. If any - /// value is present, the index of the first is returned. Negative 0 is considered smaller than positive 0. + /// The determination of the minimum element matches the IEEE 754:2019 `minimum` function. If any value equal to + /// is present, the index of the first is returned. Negative 0 is considered smaller than positive 0. /// /// /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different @@ -533,8 +501,8 @@ public static unsafe int IndexOfMin(ReadOnlySpan x) /// The index of the element in with the smallest magnitude (absolute value), or -1 if is empty. /// /// - /// The determination of the minimum magnitude matches the IEEE 754:2019 `minimumMagnitude` function. If any - /// value is present, the index of the first is returned. If two values have the same magnitude and one is positive and the other is negative, + /// The determination of the minimum magnitude matches the IEEE 754:2019 `minimumMagnitude` function. If any value equal to + /// is present, the index of the first is returned. If two values have the same magnitude and one is positive and the other is negative, /// the negative value is considered to have the smaller magnitude. /// /// @@ -595,7 +563,7 @@ public static unsafe int IndexOfMinMagnitude(ReadOnlySpan x) /// /// /// If a value equals 0, the result stored into the corresponding destination location is set to . - /// If a value is negative or NaN, the result stored into the corresponding destination location is set to . + /// If a value is negative or equal to , the result stored into the corresponding destination location is set to NaN. /// If a value is positive infinity, the result stored into the corresponding destination location is set to . /// Otherwise, if a value is positive, its natural logarithm is stored into the corresponding destination location. /// @@ -630,7 +598,7 @@ public static void Log(ReadOnlySpan x, Span destination) /// /// /// If a value equals 0, the result stored into the corresponding destination location is set to . - /// If a value is negative or NaN, the result stored into the corresponding destination location is set to . + /// If a value is negative or equal to , the result stored into the corresponding destination location is set to NaN. /// If a value is positive infinity, the result stored into the corresponding destination location is set to . /// Otherwise, if a value is positive, its natural logarithm is stored into the corresponding destination location. /// @@ -658,8 +626,8 @@ public static void Log2(ReadOnlySpan x, Span destination) /// Length of must be greater than zero. /// /// - /// The determination of the maximum element matches the IEEE 754:2019 `maximum` function. If any - /// value is present, the first is returned. Positive 0 is considered greater than negative 0. + /// The determination of the maximum element matches the IEEE 754:2019 `maximum` function. If any value equal to + /// is present, the first is returned. Positive 0 is considered greater than negative 0. /// /// /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different @@ -683,7 +651,7 @@ public static float Max(ReadOnlySpan x) => /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. /// /// - /// The determination of the maximum element matches the IEEE 754:2019 `maximum` function. If either value is , + /// The determination of the maximum element matches the IEEE 754:2019 `maximum` function. If either value is equal to , /// that value is stored as the result. Positive 0 is considered greater than negative 0. /// /// @@ -700,8 +668,8 @@ public static void Max(ReadOnlySpan x, ReadOnlySpan y, Span /// Length of must be greater than zero. /// /// - /// The determination of the maximum magnitude matches the IEEE 754:2019 `maximumMagnitude` function. If any - /// value is present, the first is returned. If two values have the same magnitude and one is positive and the other is negative, + /// The determination of the maximum magnitude matches the IEEE 754:2019 `maximumMagnitude` function. If any value equal to + /// is present, the first is returned. If two values have the same magnitude and one is positive and the other is negative, /// the positive value is considered to have the larger magnitude. /// /// @@ -721,7 +689,7 @@ public static float MaxMagnitude(ReadOnlySpan x) => /// This method effectively computes [i] = MathF.MaxMagnitude([i], [i]). /// /// - /// The determination of the maximum magnitude matches the IEEE 754:2019 `maximumMagnitude` function. If either value is , + /// The determination of the maximum magnitude matches the IEEE 754:2019 `maximumMagnitude` function. If either value is equal to , /// that value is stored as the result. If the two values have the same magnitude and one is positive and the other is negative, /// the positive value is considered to have the larger magnitude. /// @@ -742,8 +710,8 @@ public static void MaxMagnitude(ReadOnlySpan x, ReadOnlySpan y, Sp /// Length of must be greater than zero. /// /// - /// The determination of the minimum element matches the IEEE 754:2019 `minimum` function. If any - /// value is present, the first is returned. Negative 0 is considered smaller than positive 0. + /// The determination of the minimum element matches the IEEE 754:2019 `minimum` function. If any value is equal to + /// is present, the first is returned. Negative 0 is considered smaller than positive 0. /// /// /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different @@ -764,7 +732,7 @@ public static float Min(ReadOnlySpan x) => /// This method effectively computes [i] = MathF.Max([i], [i]). /// /// - /// The determination of the maximum element matches the IEEE 754:2019 `maximum` function. If either value is , + /// The determination of the maximum element matches the IEEE 754:2019 `maximum` function. If either value is equal to , /// that value is stored as the result. Positive 0 is considered greater than negative 0. /// /// @@ -784,8 +752,8 @@ public static void Min(ReadOnlySpan x, ReadOnlySpan y, Span /// Length of must be greater than zero. /// /// - /// The determination of the minimum magnitude matches the IEEE 754:2019 `minimumMagnitude` function. If any - /// value is present, the first is returned. If two values have the same magnitude and one is positive and the other is negative, + /// The determination of the minimum magnitude matches the IEEE 754:2019 `minimumMagnitude` function. If any value equal to + /// is present, the first is returned. If two values have the same magnitude and one is positive and the other is negative, /// the negative value is considered to have the smaller magnitude. /// /// @@ -805,7 +773,7 @@ public static float MinMagnitude(ReadOnlySpan x) => /// This method effectively computes [i] = MathF.MinMagnitude([i], [i]). /// /// - /// The determination of the maximum magnitude matches the IEEE 754:2019 `minimumMagnitude` function. If either value is , + /// The determination of the maximum magnitude matches the IEEE 754:2019 `minimumMagnitude` function. If either value is equal to , /// that value is stored as the result. If the two values have the same magnitude and one is positive and the other is negative, /// the negative value is considered to have the smaller magnitude. /// @@ -834,11 +802,7 @@ public static void MinMagnitude(ReadOnlySpan x, ReadOnlySpan y, Sp /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. /// /// - /// If either of the element-wise input values is , the resulting element-wise value is . - /// - /// - /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different - /// operating systems or architectures. + /// If either of the element-wise input values is equal to , the resulting element-wise value is also NaN. /// /// public static void Multiply(ReadOnlySpan x, ReadOnlySpan y, Span destination) => @@ -858,11 +822,7 @@ public static void Multiply(ReadOnlySpan x, ReadOnlySpan y, Span and may not overlap; if they do, behavior is undefined. /// /// - /// If either of the element-wise input values is , the resulting element-wise value is . - /// - /// - /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different - /// operating systems or architectures. + /// If either of the element-wise input values is equal to , the resulting element-wise value is also NaN. /// /// public static void Multiply(ReadOnlySpan x, float y, Span destination) => @@ -883,14 +843,7 @@ public static void Multiply(ReadOnlySpan x, float y, Span destinat /// , , and may overlap, but none of them may overlap with ; if they do, behavior is undefined. /// /// - /// If any of the element-wise input values is , the resulting element-wise value is . - /// - /// - /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different - /// operating systems or architectures. On some platforms, this may perform the operation rounded as one ternary operation, such that it computes ( * ) - /// as if to infinite precision, adds to that result as if to infinite precision, and finally rounds to the nearest representable value. On architectures where such - /// a fused multiply-add is not supported, this will compute ( * ) as if to infinite precision, round the result to the nearest representable value, - /// add to the rounded result as if to infinite precision, and finally round to the nearest representable value. + /// If either of the element-wise input values is equal to , the resulting element-wise value is also NaN. /// /// public static void MultiplyAdd(ReadOnlySpan x, ReadOnlySpan y, ReadOnlySpan addend, Span destination) => @@ -912,14 +865,7 @@ public static void MultiplyAdd(ReadOnlySpan x, ReadOnlySpan y, Rea /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. /// /// - /// If any of the element-wise input values is , the resulting element-wise value is . - /// - /// - /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different - /// operating systems or architectures. On some platforms, this may perform the operation rounded as one ternary operation, such that it computes ( * ) - /// as if to infinite precision, adds to that result as if to infinite precision, and finally rounds to the nearest representable value. On architectures where such - /// a fused multiply-add is not supported, this will compute ( * ) as if to infinite precision, round the result to the nearest representable value, - /// add to the rounded result as if to infinite precision, and finally round to the nearest representable value. + /// If either of the element-wise input values is equal to , the resulting element-wise value is also NaN. /// /// public static void MultiplyAdd(ReadOnlySpan x, ReadOnlySpan y, float addend, Span destination) => @@ -940,14 +886,7 @@ public static void MultiplyAdd(ReadOnlySpan x, ReadOnlySpan y, flo /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. /// /// - /// If any of the element-wise input values is , the resulting element-wise value is . - /// - /// - /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different - /// operating systems or architectures. On some platforms, this may perform the operation rounded as one ternary operation, such that it computes ( * ) - /// as if to infinite precision, adds to that result as if to infinite precision, and finally rounds to the nearest representable value. On architectures where such - /// a fused multiply-add is not supported, this will compute ( * ) as if to infinite precision, round the result to the nearest representable value, - /// add to the rounded result as if to infinite precision, and finally round to the nearest representable value. + /// If either of the element-wise input values is equal to , the resulting element-wise value is also NaN. /// /// public static void MultiplyAdd(ReadOnlySpan x, float y, ReadOnlySpan addend, Span destination) => @@ -965,11 +904,7 @@ public static void MultiplyAdd(ReadOnlySpan x, float y, ReadOnlySpan and may not overlap; if they do, behavior is undefined. /// /// - /// If any of the element-wise input values is , the resulting element-wise value is . - /// - /// - /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different - /// operating systems or architectures. + /// If any of the element-wise input values is equal to , the resulting element-wise value is also NaN. /// /// public static void Negate(ReadOnlySpan x, Span destination) => @@ -985,7 +920,7 @@ public static void Negate(ReadOnlySpan x, Span destination) => /// It corresponds to the nrm2 method defined by BLAS1. /// /// - /// If any of the input values is , the result value is . + /// If any of the input values is equal to , the result value is also NaN. /// /// /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different @@ -1001,7 +936,7 @@ public static float Norm(ReadOnlySpan x) => /// Length of must be greater than zero. /// /// - /// If any of the input values is , the result value is . + /// If any of the input values is equal to , the result value is also NaN. /// /// /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different @@ -1218,11 +1153,7 @@ public static void SoftMax(ReadOnlySpan x, Span destination) /// and may overlap, but neither may overlap with ; if they do, behavior is undefined. /// /// - /// If either of the element-wise input values is , the resulting element-wise value is . - /// - /// - /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different - /// operating systems or architectures. + /// If either of the element-wise input values is equal to , the resulting element-wise value is also NaN. /// /// public static void Subtract(ReadOnlySpan x, ReadOnlySpan y, Span destination) => @@ -1241,11 +1172,7 @@ public static void Subtract(ReadOnlySpan x, ReadOnlySpan y, Span and may not overlap; if they do, behavior is undefined. /// /// - /// If either of the element-wise input values is , the resulting element-wise value is . - /// - /// - /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different - /// operating systems or architectures. + /// If either of the element-wise input values is equal to , the resulting element-wise value is also NaN. /// /// public static void Subtract(ReadOnlySpan x, float y, Span destination) => @@ -1256,7 +1183,7 @@ public static void Subtract(ReadOnlySpan x, float y, Span destinat /// The result of adding all elements in , or zero if is empty. /// /// - /// If any of the values in the input is , the result is . + /// If any of the values in the input is equal to , the result is also NaN. /// /// /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different @@ -1322,7 +1249,7 @@ public static float SumOfSquares(ReadOnlySpan x) => /// /// If a value is equal to , the corresponding destination location is set to -1. /// If a value is equal to , the corresponding destination location is set to 1. - /// If a value is , the corresponding destination location is set to . + /// If a value is equal to , the corresponding destination location is set to NaN. /// /// /// The angles in x must be in radians. Multiply by /180 to convert degrees to radians. diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netcore.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netcore.cs index 8520aa78f9c9cc..bed07eedfefd1e 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netcore.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netcore.cs @@ -1918,11 +1918,11 @@ public static Vector512 Invoke(Vector512 x, Vector512 y) private readonly struct MultiplyAddOperator : ITernaryOperator { - public static float Invoke(float x, float y, float z) => MathF.FusedMultiplyAdd(x, y, z); - public static Vector128 Invoke(Vector128 x, Vector128 y, Vector128 z) => FusedMultiplyAdd(x, y, z); - public static Vector256 Invoke(Vector256 x, Vector256 y, Vector256 z) => FusedMultiplyAdd(x, y, z); + public static float Invoke(float x, float y, float z) => (x * y) + z; + public static Vector128 Invoke(Vector128 x, Vector128 y, Vector128 z) => (x * y) + z; + public static Vector256 Invoke(Vector256 x, Vector256 y, Vector256 z) => (x * y) + z; #if NET8_0_OR_GREATER - public static Vector512 Invoke(Vector512 x, Vector512 y, Vector512 z) => FusedMultiplyAdd(x, y, z); + public static Vector512 Invoke(Vector512 x, Vector512 y, Vector512 z) => (x * y) + z; #endif } From bccbdfe5293953bbadeecb7ad9bd2bcb413c5693 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Thu, 28 Sep 2023 16:53:55 -0400 Subject: [PATCH 3/3] Address PR feedback --- .../src/System/Numerics/Tensors/TensorPrimitives.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.cs index 807dd2edadd99a..0da8b6dfcdec2a 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.cs @@ -146,7 +146,7 @@ public static void AddMultiply(ReadOnlySpan x, float y, ReadOnlySpan, the result stored into the corresponding destination location is also NaN. /// /// - /// The angles in x must be in radians. Multiply by /180 to convert degrees to radians. + /// The angles in x must be in radians. Use or multiply by /180 to convert degrees to radians. /// /// /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different @@ -1076,7 +1076,7 @@ public static void Sigmoid(ReadOnlySpan x, Span destination) /// the corresponding destination location is set to that value. /// /// - /// The angles in x must be in radians. Multiply by /180 to convert degrees to radians. + /// The angles in x must be in radians. Use or multiply by /180 to convert degrees to radians. /// /// /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different @@ -1252,7 +1252,7 @@ public static float SumOfSquares(ReadOnlySpan x) => /// If a value is equal to , the corresponding destination location is set to NaN. /// /// - /// The angles in x must be in radians. Multiply by /180 to convert degrees to radians. + /// The angles in x must be in radians. Use or multiply by /180 to convert degrees to radians. /// /// /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different