閱讀英文

共用方式為


一般數學

.NET 7 將新的數學相關泛型介面引進基底類別庫。 這些介面的可用性表示您可以將泛型型別或方法的型別參數限制為「類似數字」。 此外,C# 11 和更新版本可讓您定義 static virtual 介面成員。 由於運算子必須宣告為 static,所以這個新的 C# 功能可讓運算子在類似數字類型的新介面中進行宣告。

這些創新功能可讓您一般執行數學運算,也就是說,不需要知道您所使用的確切類型。 例如,如果您想要撰寫一個新增兩個數字的方法,則先前必須為每個型別新增方法的多載 (例如,static int Add(int first, int second)static float Add(float first, float second))。 現在您可以撰寫單一泛型方法,其中 type 參數受限為類似數字的型別。 例如:

C#
static T Add<T>(T left, T right)
    where T : INumber<T>
{
    return left + right;
}

在此方法中,型別參數 T 受限於實作新 INumber<TSelf> 介面的類型。 INumber<TSelf> 會實作 IAdditionOperators<TSelf,TOther,TResult> 介面,其中包含 + 運算子。 這可讓方法以一般方式新增兩個數字。 方法可以搭配任何 .NET 的內建數字類型使用,因為其都已更新為在 .NET 7 中實作 INumber<TSelf>

程式庫作者會受益於一般數學介面,因為這些作者可藉由移除「備援」多載來簡化其程式碼基底。 其他開發人員會間接受益,因為其取用的 API 可能會開始支援更多類型。

介面

這些介面的設計目的是要達到足夠的精細度,讓使用者可以在最上層定義自己的介面,同時要達到足夠的細微度,讓使用者能容易取用。 在該範圍內,會有幾個大部分使用者都會進行互動的核心數值介面,例如 INumber<TSelf>IBinaryInteger<TSelf>。 更精細的介面 (例如 IAdditionOperators<TSelf,TOther,TResult>ITrigonometricFunctions<TSelf>) 支援這些類型,且可供定義其專屬網域特定數值介面的開發人員使用。

數值介面

本節描述 System.Numerics 中的介面,當中描述類似數字的類型及其可用的功能。

介面名稱 描述
IBinaryFloatingPointIeee754<TSelf> 公開實作 IEEE 754 標準的「二進位」浮點類型1通用的 API。
IBinaryInteger<TSelf> 公開二進位整數2通用的 API。
IBinaryNumber<TSelf> 公開二進位數字通用的 API。
IFloatingPoint<TSelf> 公開浮點類型通用的 API。
IFloatingPointIeee754<TSelf> 公開實作 IEEE 754 標準的浮點類型通用的 API。
INumber<TSelf> 公開類似數字類型的通用 API (實際為「實數」數字網域)。
INumberBase<TSelf> 公開所有數字類型的通用 API (實際為「複數」數字網域)。
ISignedNumber<TSelf> 公開所有帶正負號數字類型的通用 API (例如 NegativeOne 的概念)。
IUnsignedNumber<TSelf> 公開所有未帶正負號數字類型的通用 API。
IAdditiveIdentity<TSelf,TResult> 公開 (x + T.AdditiveIdentity) == x 的概念。
IMinMaxValue<TSelf> 公開 T.MinValueT.MaxValue 的概念。
IMultiplicativeIdentity<TSelf,TResult> 公開 (x * T.MultiplicativeIdentity) == x 的概念。

1二進位浮點類型Double (double)、HalfSingle (float)。

2二進位整數類型Byte (byte)、Int16 (short)、Int32 (int)、Int64 (long)、Int128IntPtr (nint)、SByte (sbyte)、UInt16 (ushort)、UInt32 (uint)、UInt64 (ulong)、UInt128UIntPtr (nuint)。

您最有可能直接使用的介面是 INumber<TSelf>,其大致對應至「實數」。 如果類型實作這個介面,表示值具有符號 (這包含 unsigned 類型,會視為正),且可以與相同類型的其他值進行比較。 INumberBase<TSelf> 提供更進階的概念,例如「複數」以及「虛數」,例如負數的平方根。 會建立其他介面 (例如 IFloatingPointIeee754<TSelf>),因為並非所有作業對所有數字類型都有意義,例如,計算數字的底板僅對浮點類型有意義。 在 .NET 基底類別庫中,浮點類型 Double 會實作 IFloatingPointIeee754<TSelf>Int32 不會實作。

其他各種類型也會實作數個介面,包括 CharDateOnlyDateTimeDateTimeOffsetDecimalGuidTimeOnlyTimeSpan

下表顯示每個介面公開的一些核心 API。

介面 API 名稱 描述
IBinaryInteger<TSelf> DivRem 同時計算商數和餘數。
LeadingZeroCount 計算二進位表示法中的前置零位元數。
PopCount 計算二進位表示法中的設定位元數。
RotateLeft 將位元向左旋轉,有時也稱為左循環移位。
RotateRight 將位元向右旋轉,有時也稱為右循環移位。
TrailingZeroCount 計算二進位表示法中的後置零位元數。
IFloatingPoint<TSelf> Ceiling 將值四捨五入為正無限大。 +4.5 會變成 +5,而 -4.5 會變成 -4。
Floor 將值四捨五入為負無限大。 +4.5 會變成 +4,而 -4.5 會變成 -5。
Round 使用指定的進位模式將值四捨五入值。
Truncate 將值四捨五入為零。 +4.5 會變成 +4,而 -4.5 會變成 -4。
IFloatingPointIeee754<TSelf> E 取得值,表示類型的 Euler 數字。
Epsilon 針對類型取得大於零的最小可表示值。
NaN 針對類型取得表示 NaN 的值。
NegativeInfinity 針對類型取得表示 -Infinity 的值。
NegativeZero 針對類型取得表示 -Zero 的值。
Pi 針對類型取得表示 Pi 的值。
PositiveInfinity 針對類型取得表示 +Infinity 的值。
Tau 針對類型取得表示 Tau (2 * Pi) 的值。
(其他) (實作函式介面下所列的完整介面集。)
INumber<TSelf> Clamp 將值限制為不超過且不低於指定的最小值和最大值。
CopySign 將指定值的正負號設定為與另一個指定的值相同。
Max 傳回兩個值的較大值,如果任一輸入為 NaN,則傳回 NaN
MaxNumber 傳回兩個值的較大值,如果一個輸入為 NaN,則傳回數字。
Min 傳回兩個值的較小值,如果任一輸入為 NaN,則傳回 NaN
MinNumber 傳回兩個值的較小值,如果一個輸入為 NaN,則傳回數字。
Sign 針對負值傳回 -1、針對零傳回 0,以及針對正值則傳回 +1。
INumberBase<TSelf> One 取得類型的值 1。
Radix 取得類型的基數或基底。 Int32 會傳回 2。 Decimal 傳回 10。
Zero 取得類型的值 0。
CreateChecked 建立值,如果輸入無法容納,則會擲回 OverflowException1
CreateSaturating 建立值,如果輸入無法容納,則限制為 T.MinValueT.MaxValue1
CreateTruncating 從另一個值建立值,如果輸入無法容納,請換行。1
IsComplexNumber 如果值具有非零實數部分和非零虛數部分,則傳回 true。
IsEvenInteger 如果值為偶數整數,則傳回 true。 2.0 會傳回 true,而 2.2 會傳回 false
IsFinite 如果值並非無限且非 NaN,則傳回 true。
IsImaginaryNumber 如果值具有零個實數部分,則傳回 true。 這表示 0 為虛構而 1 + 1i 則非虛構。
IsInfinity 如果值代表無限大,則傳回 true。
IsInteger 如果值為整數,則傳回 true。 2.0 和 3.0 會傳回 true,而 2.2 和 3.1 則會傳回 false
IsNaN 如果值代表 NaN,則傳回 true。
IsNegative 如果值為負數,則傳回 true。 這包括 -0.0。
IsPositive 如果值為正數,則傳回 true。 這包括 0 和 +0.0。
IsRealNumber 如果值為零虛數部分,則傳回 true。 這表示 0 與所有 INumber<T> 類型皆為實數。
IsZero 如果值代表零,則傳回 true。 這包括 0、+0.0 和 -0.0。
MaxMagnitude 傳回具有較大絕對值的值,如果任一輸入為 NaN,則傳回 NaN
MaxMagnitudeNumber 傳回具有較大絕對值的值,如果一個輸入為 NaN,則傳回數字。
MinMagnitude 傳回具有較小絕對值的值,如果任一輸入為 NaN,則傳回 NaN
MinMagnitudeNumber 傳回具有較小絕對值的值,如果一個輸入為 NaN,則傳回數字。
ISignedNumber<TSelf> NegativeOne 取得類型的值 -1。

1若要協助了解三種 Create* 方法的行為,請考慮下列範例。

假設值太大時的範例:

  • byte.CreateChecked(384) 將會擲回 OverflowException
  • byte.CreateSaturating(384) 會傳回 255,因為 384 大於 Byte.MaxValue (也就是 255)。
  • byte.CreateTruncating(384) 會傳回 128,因為其採用最低 8 位元 (384 具有十六進位表示法 0x0180,而最低 8 位元則為 0x80,也就是 128)。

假設值太小時的範例:

  • byte.CreateChecked(-384) 將會擲回 OverflowException
  • byte.CreateSaturating(-384) 會傳回 0,因為 -384 小於 Byte.MinValue (也就是 0)。
  • byte.CreateTruncating(-384) 會傳回 128,因為其採用最低 8 位元 (384 具有十六進位表示法 0xFE80,而最低 8 位元則為 0x80,也就是 128)。

Create* 方法針對 IEEE 754 浮點類型也有一些特殊考量 (例如 floatdouble),因為其具有特殊值 PositiveInfinityNegativeInfinityNaN。 這三個 Create* API 的行為都是 CreateSaturating。 此外,雖然 MinValueMaxValue 代表最大的負數/正數「正規數」數字,但實際的最小值和最大值為 NegativeInfinityPositiveInfinity,因此會改為限制這些值。

運算子介面

運算子介面會對應至 C# 語言可用的各種運算子。

  • 其不會明確配對運算 (例如乘法和除法),因為這對所有類型都不正確。 例如,Matrix4x4 * Matrix4x4 為有效,但 Matrix4x4 / Matrix4x4 為無效。
  • 其通常允許輸入和結果類型區隔來支援案例,例如分割兩個整數來取得 double (例如,3 / 2 = 1.5) 或計算一組整數的平均值。

注意

除了一般未核取的運算子之外,有些介面還會定義已檢查的運算子。 會在已檢查的內容中呼叫已檢查的運算子,並允許使用者定義型別定義溢位行為。 如果您實作已檢查的運算子 (例如,CheckedSubtraction(TSelf, TOther)),則您也必須實作未檢查的運算子 (例如,Subtraction(TSelf, TOther))。

函式介面

函式介面會定義通用數學 API,可更廣泛而非特定套用至數值介面。 這些介面都是由 IFloatingPointIeee754<TSelf> 所實作,未來可能會由其他相關類型實作。

介面名稱 描述
IExponentialFunctions<TSelf> 公開支援 e^xe^x - 12^x2^x - 110^x10^x - 1 的指數函式。
IHyperbolicFunctions<TSelf> 公開支援 acosh(x)asinh(x)atanh(x)cosh(x)sinh(x)tanh(x) 的雙曲線函式。
ILogarithmicFunctions<TSelf> 公開支援 ln(x)ln(x + 1)log2(x)log2(x + 1)log10(x)log10(x + 1) 的對數函式。
IPowerFunctions<TSelf> 公開支援 x^y 的冪函式。
IRootFunctions<TSelf> 公開支援 cbrt(x)sqrt(x) 的根函式。
ITrigonometricFunctions<TSelf> 公開支援 acos(x)asin(x)atan(x)cos(x)sin(x)tan(x) 的三角函數。

剖析和格式化介面

剖析和格式化是程式設計的核心概念。 將使用者輸入轉換成指定的類型或向使用者顯示類型時,通常會用到這些介面。 這些介面都在 System 命名空間中。

介面名稱 描述
IParsable<TSelf> 公開 T.Parse(string, IFormatProvider)T.TryParse(string, IFormatProvider, out TSelf) 的支援。
ISpanParsable<TSelf> 公開 T.Parse(ReadOnlySpan<char>, IFormatProvider)T.TryParse(ReadOnlySpan<char>, IFormatProvider, out TSelf) 的支援。
IFormattable1 公開 value.ToString(string, IFormatProvider) 的支援。
ISpanFormattable1 公開 value.TryFormat(Span<char>, out int, ReadOnlySpan<char>, IFormatProvider) 的支援。

1這個並非新的介面,也不是泛型介面。 不過,這個介面是由所有數字類型所實作,並代表 IParsable 的反向運算。

例如,下列程式會接受兩個數字做為輸入,並使用泛型方法從主控台加以讀取,其中型別參數會限制為 IParsable<TSelf>。 其會使用泛型方法計算平均值,其中輸入和結果值的型別參數會限制為 INumber<TSelf>,然後將結果顯示至主控台。

C#
using System.Globalization;
using System.Numerics;

static TResult Average<T, TResult>(T first, T second)
    where T : INumber<T>
    where TResult : INumber<TResult>
{
    return TResult.CreateChecked( (first + second) / T.CreateChecked(2) );
}

static T ParseInvariant<T>(string s)
    where T : IParsable<T>
{
    return T.Parse(s, CultureInfo.InvariantCulture);
}

Console.Write("First number: ");
var left = ParseInvariant<float>(Console.ReadLine());

Console.Write("Second number: ");
var right = ParseInvariant<float>(Console.ReadLine());

Console.WriteLine($"Result: {Average<float, float>(left, right)}");

/* This code displays output similar to:

First number: 5.0
Second number: 6
Result: 5.5
*/

另請參閱