Ogólna matematyka
Platforma .NET 7 wprowadza nowe interfejsy ogólne związane z matematyką do biblioteki klas bazowych. Dostępność tych interfejsów oznacza, że można ograniczyć parametr typu typu lub metody, aby był "podobny do liczby". Ponadto język C# 11 i nowsze umożliwiają definiowanie static virtual
elementów członkowskich interfejsu. Ponieważ operatory muszą być zadeklarowane jako static
, ta nowa funkcja języka C# umożliwia zadeklarowanie operatorów w nowych interfejsach dla typów przypominających liczbę.
Razem te innowacje umożliwiają ogólne wykonywanie operacji matematycznych — czyli bez konieczności znajomości dokładnego typu, z którym pracujesz. Jeśli na przykład chcesz napisać metodę, która dodaje dwie liczby, wcześniej trzeba było dodać przeciążenie metody dla każdego typu (na przykład static int Add(int first, int second)
i static float Add(float first, float second)
). Teraz możesz napisać pojedynczą, ogólną metodę, w której parametr typu jest ograniczony do typu przypominającego liczbę. Na przykład:
static T Add<T>(T left, T right)
where T : INumber<T>
{
return left + right;
}
W tej metodzie parametr T
typu jest ograniczony do typu, który implementuje nowy INumber<TSelf> interfejs. INumber<TSelf> implementuje IAdditionOperators<TSelf,TOther,TResult> interfejs, który zawiera operator +. Dzięki tej metodzie można w sposób ogólny dodać dwie liczby. Metodę można użyć z dowolnym elementem . Wbudowane typy liczbowe platformy NET, ponieważ wszystkie zostały zaktualizowane do implementacji INumber<TSelf> na platformie .NET 7.
Autorzy bibliotek będą korzystać z większości ogólnych interfejsów matematycznych, ponieważ mogą uprościć bazę kodu, usuwając przeciążenia "nadmiarowe". Inni deweloperzy będą korzystać pośrednio, ponieważ używane przez nich interfejsy API mogą zacząć obsługiwać więcej typów.
Interfejsy
Interfejsy zostały zaprojektowane tak, aby były wystarczająco szczegółowe, aby użytkownicy mogli definiować własne interfejsy na górze, a jednocześnie są wystarczająco szczegółowe, że są łatwe do spożycia. W tym zakresie istnieje kilka podstawowych interfejsów liczbowych, z którymi większość użytkowników będzie korzystać, takich jak INumber<TSelf> i IBinaryInteger<TSelf>. Bardziej szczegółowe interfejsy, takie jak IAdditionOperators<TSelf,TOther,TResult> i ITrigonometricFunctions<TSelf>, obsługują te typy i są dostępne dla deweloperów, którzy definiują własne interfejsy liczbowe specyficzne dla domeny.
Interfejsy liczbowe
W tej sekcji opisano interfejsy opisane w System.Numerics nich typy podobne do liczb i dostępne dla nich funkcje.
Nazwa interfejsu | opis |
---|---|
IBinaryFloatingPointIeee754<TSelf> | Uwidacznia interfejsy API wspólne dla binarnych typówzmiennoprzecinkowych 1, które implementują standard IEEE 754. |
IBinaryInteger<TSelf> | Uwidacznia interfejsy API wspólne dla liczbbinarnych 2. |
IBinaryNumber<TSelf> | Uwidacznia interfejsy API wspólne dla liczb binarnych. |
IFloatingPoint<TSelf> | Uwidacznia interfejsy API wspólne dla typów zmiennoprzecinkowych. |
IFloatingPointIeee754<TSelf> | Uwidacznia interfejsy API wspólne dla typów zmiennoprzecinkowych, które implementują standard IEEE 754. |
INumber<TSelf> | Uwidacznia interfejsy API wspólne dla porównywalnych typów liczb (w rzeczywistości "domena liczb rzeczywistych"). |
INumberBase<TSelf> | Uwidacznia interfejsy API wspólne dla wszystkich typów liczb (w rzeczywistości "złożona" domena liczb). |
ISignedNumber<TSelf> | Uwidacznia interfejsy API wspólne dla wszystkich typów cyfr podpisanych (takich jak koncepcja ).NegativeOne |
IUnsignedNumber<TSelf> | Uwidacznia interfejsy API wspólne dla wszystkich niepodpisanych typów liczb. |
IAdditiveIdentity<TSelf,TResult> | Uwidacznia koncepcję .(x + T.AdditiveIdentity) == x |
IMinMaxValue<TSelf> | Uwidacznia koncepcję elementów T.MinValue i T.MaxValue . |
IMultiplicativeIdentity<TSelf,TResult> | Uwidacznia koncepcję .(x * T.MultiplicativeIdentity) == x |
1Binarne typy zmiennoprzecinkowe to Double (double
), Halfi Single (float
).
2Typy liczb całkowitych binarnych to Byte (byte
), Int16 (short
), Int32 (int
), (), (long
), Int64 (), IntPtrInt128(sbyte
UInt16nint
SByte), (), (uint
UInt32ushort
), UInt64ulong
() UInt128i UIntPtr (nuint
).
Interfejs, którego najprawdopodobniej używasz bezpośrednio, to INumber<TSelf>, który w przybliżeniu odpowiada liczbie rzeczywistej. Jeśli typ implementuje ten interfejs, oznacza to, że wartość ma znak (obejmuje unsigned
to typy, które są uważane za dodatnie) i mogą być porównywane z innymi wartościami tego samego typu. INumberBase<TSelf> nadaje bardziej zaawansowane koncepcje, takie jak liczby złożone i wyimaginowane , na przykład pierwiastek kwadratowy liczby ujemnej. Inne interfejsy, takie jak IFloatingPointIeee754<TSelf>, zostały utworzone, ponieważ nie wszystkie operacje mają sens dla wszystkich typów liczb — na przykład obliczanie podłogi liczby ma sens tylko dla typów zmiennoprzecinkowych. W bibliotece klas bazowych platformy .NET typ Double zmiennoprzecinkowa implementuje IFloatingPointIeee754<TSelf> , ale Int32 nie.
Kilka interfejsów jest również implementowanych przez różne inne typy, w tym Char, , DateTimeDecimalDateTimeOffsetGuidDateOnly, TimeOnlyi .TimeSpan
W poniższej tabeli przedstawiono niektóre podstawowe interfejsy API uwidocznione przez każdy interfejs.
Interfejs | Nazwa interfejsu API | opis |
---|---|---|
IBinaryInteger<TSelf> | DivRem |
Oblicza iloraz i pozostałą część. |
LeadingZeroCount |
Zlicza liczbę bitów zer wiodących w reprezentacji binarnej. | |
PopCount |
Zlicza bity ustawione w reprezentacji binarnej. | |
RotateLeft |
Obraca bity w lewo, czasami nazywane również okrągłym przesunięciem w lewo. | |
RotateRight |
Obraca bity w prawo, czasami nazywane również okrągłym przesunięciem w prawo. | |
TrailingZeroCount |
Zlicza liczbę bitów końcowych zero w reprezentacji binarnej. | |
IFloatingPoint<TSelf> | Ceiling |
Zaokrągla wartość w kierunku nieskończoności dodatniej. +4.5 staje się +5, a wartość -4.5 staje się -4. |
Floor |
Zaokrągla wartość w kierunku nieskończoności ujemnej. +4.5 staje się +4, a wartość -4.5 staje się -5. | |
Round |
Zaokrągla wartość przy użyciu określonego trybu zaokrąglania. | |
Truncate |
Zaokrągla wartość do zera. +4.5 staje się +4, a wartość -4.5 staje się -4. | |
IFloatingPointIeee754<TSelf> | E |
Pobiera wartość reprezentującą liczbę Eulera dla typu. |
Epsilon |
Pobiera najmniejszą reprezentującą wartość większą niż zero dla typu. | |
NaN |
Pobiera wartość reprezentującą NaN typ. |
|
NegativeInfinity |
Pobiera wartość reprezentującą -Infinity typ. |
|
NegativeZero |
Pobiera wartość reprezentującą -Zero typ. |
|
Pi |
Pobiera wartość reprezentującą Pi typ. |
|
PositiveInfinity |
Pobiera wartość reprezentującą +Infinity typ. |
|
Tau |
Pobiera wartość reprezentującą Tau (2 * Pi ) dla typu. |
|
(Inne) | (Implementuje pełny zestaw interfejsów wymienionych w obszarze Interfejsy funkcji). | |
INumber<TSelf> | Clamp |
Ogranicza wartość do nie więcej i nie mniej niż określona wartość minimalna i maksymalna. |
CopySign |
Ustawia znak określonej wartości na taki sam jak inna określona wartość. | |
Max |
Zwraca większą z dwóch wartości, zwracając NaN wartość , jeśli jeden z danych wejściowych to NaN . |
|
MaxNumber |
Zwraca większą z dwóch wartości, zwracając liczbę, jeśli jedno dane wejściowe to NaN . |
|
Min |
Zwraca mniejszą z dwóch wartości, zwracając NaN wartość , jeśli jeden z danych wejściowych to NaN . |
|
MinNumber |
Zwraca mniejszą z dwóch wartości, zwracając liczbę, jeśli jedno dane wejściowe to NaN . |
|
Sign |
Zwraca wartość -1 dla wartości ujemnych, 0 dla zera i +1 dla wartości dodatnich. | |
INumberBase<TSelf> | One |
Pobiera wartość 1 dla typu. |
Radix |
Pobiera promienie lub podstawę dla typu. Int32 zwraca wartość 2. Decimal zwraca 10. | |
Zero |
Pobiera wartość 0 dla typu. | |
CreateChecked |
Tworzy wartość, zgłaszając OverflowException wartość, jeśli dane wejściowe nie mogą pasować.1 | |
CreateSaturating |
Tworzy wartość, zaciskanie do T.MinValue lub T.MaxValue jeśli dane wejściowe nie mogą się zmieścić.1 |
|
CreateTruncating |
Tworzy wartość z innej wartości, opakowujące się, jeśli dane wejściowe nie mogą pasować.1 | |
IsComplexNumber |
Zwraca wartość true, jeśli wartość ma niezerową część rzeczywistą i niezerową część wyimaginowaną. | |
IsEvenInteger |
Zwraca wartość true, jeśli wartość jest parzystą liczbą całkowitą. Funkcja 2.0 zwraca wartość true , a wartość 2.2 zwraca wartość false . |
|
IsFinite |
Zwraca wartość true, jeśli wartość nie jest nieskończona, a nie NaN . |
|
IsImaginaryNumber |
Zwraca wartość true, jeśli wartość ma wartość zero rzeczywistej. Oznacza 0 to, że jest wyimaginowany i 1 + 1i nie jest. |
|
IsInfinity |
Zwraca wartość true, jeśli wartość reprezentuje nieskończoność. | |
IsInteger |
Zwraca wartość true, jeśli wartość jest liczbą całkowitą. 2.0 i 3.0 zwracają wartości true , a 2.2 i 3.1 zwracają wartość false . |
|
IsNaN |
Zwraca wartość true, jeśli wartość reprezentuje NaN wartość . |
|
IsNegative |
Zwraca wartość true, jeśli wartość jest ujemna. Obejmuje to wartość -0.0. | |
IsPositive |
Zwraca wartość true, jeśli wartość jest dodatnia. Obejmuje to 0 i +0.0. | |
IsRealNumber |
Zwraca wartość true, jeśli wartość ma zerową część wyimaginowaną. Oznacza to, że wartość 0 jest prawdziwa, podobnie jak wszystkie INumber<T> typy. |
|
IsZero |
Zwraca wartość true, jeśli wartość reprezentuje zero. Obejmuje to wartości 0, +0.0 i -0.0. | |
MaxMagnitude |
Zwraca wartość z większą wartością bezwzględną, zwracając NaN wartość , jeśli dane wejściowe to NaN . |
|
MaxMagnitudeNumber |
Zwraca wartość z większą wartością bezwzględną, zwracając liczbę, jeśli jedno dane wejściowe to NaN . |
|
MinMagnitude |
Zwraca wartość z mniejszą wartością bezwzględną, zwracając NaN wartość , jeśli dane wejściowe to NaN . |
|
MinMagnitudeNumber |
Zwraca wartość z mniejszą wartością bezwzględną, zwracając liczbę, jeśli jedno dane wejściowe to NaN . |
|
ISignedNumber<TSelf> | NegativeOne |
Pobiera wartość -1 dla typu. |
1Aby ułatwić zrozumienie zachowania trzech Create*
metod, rozważ następujące przykłady.
Przykład, gdy dana wartość jest zbyt duża:
byte.CreateChecked(384)
element zgłosi element OverflowException.byte.CreateSaturating(384)
Zwraca wartość 255, ponieważ wartość 384 jest większa niż Byte.MaxValue (czyli 255).byte.CreateTruncating(384)
Zwraca wartość 128, ponieważ przyjmuje najniższe 8 bitów (384 ma reprezentację0x0180
szesnastkową , a najniższa 8 bitów to0x80
, czyli 128).
Przykład, gdy dana wartość jest za mała:
byte.CreateChecked(-384)
element zgłosi element OverflowException.byte.CreateSaturating(-384)
Zwraca wartość 0, ponieważ wartość -384 jest mniejsza niż Byte.MinValue (czyli 0).byte.CreateTruncating(-384)
Zwraca wartość 128, ponieważ przyjmuje najniższe 8 bitów (384 ma reprezentację0xFE80
szesnastkową , a najniższa 8 bitów to0x80
, czyli 128).
Metody Create*
mają również pewne specjalne zagadnienia dotyczące typów zmiennoprzecinkowych IEEE 754, takich jak float
i double
, ponieważ mają specjalne wartości PositiveInfinity
, NegativeInfinity
i NaN
. Wszystkie trzy Create*
interfejsy API zachowują się jako CreateSaturating
. Ponadto, podczas gdy MinValue
i MaxValue
reprezentują największą ujemną/dodatnią liczbę "normalną", rzeczywiste wartości minimalne i maksymalne są NegativeInfinity
i PositiveInfinity
, więc zamiast tego zaciskają się do tych wartości.
Interfejsy operatorów
Interfejsy operatora odpowiadają różnym operatorom dostępnym dla języka C#.
- Jawnie nie łączą one operacji, takich jak mnożenie i dzielenie, ponieważ nie jest to poprawne dla wszystkich typów. Na przykład
Matrix4x4 * Matrix4x4
jest prawidłowy, aleMatrix4x4 / Matrix4x4
nie jest prawidłowy. - Zazwyczaj umożliwiają one różnice między typami danych wejściowych i wynikowych w celu obsługi scenariuszy, takich jak dzielenie dwóch liczb całkowitych w celu uzyskania
double
wartości , na przykład3 / 2 = 1.5
, lub obliczanie średniej zestawu liczb całkowitych.
Nazwa interfejsu | Zdefiniowane operatory |
---|---|
IAdditionOperators<TSelf,TOther,TResult> | x + y |
IBitwiseOperators<TSelf,TOther,TResult> | x & y , 'x | y', x ^ y i ~x |
IComparisonOperators<TSelf,TOther,TResult> | x < y , x > y , x <= y i x >= y |
IDecrementOperators<TSelf> | --x i x-- |
IDivisionOperators<TSelf,TOther,TResult> | x / y |
IEqualityOperators<TSelf,TOther,TResult> | x == y i x != y |
IIncrementOperators<TSelf> | ++x i x++ |
IModulusOperators<TSelf,TOther,TResult> | x % y |
IMultiplyOperators<TSelf,TOther,TResult> | x * y |
IShiftOperators<TSelf,TOther,TResult> | x << y i x >> y |
ISubtractionOperators<TSelf,TOther,TResult> | x - y |
IUnaryNegationOperators<TSelf,TResult> | -x |
IUnaryPlusOperators<TSelf,TResult> | +x |
Uwaga
Niektóre interfejsy definiują operatora zaznaczonego oprócz zwykłego nieznaczonego operatora. Sprawdzone operatory są wywoływane w zaznaczonych kontekstach i umożliwiają definiowanie zachowania przepełnienia zdefiniowanego przez użytkownika. Jeśli na przykład zaimplementujesz sprawdzony operator , CheckedSubtraction(TSelf, TOther)musisz również zaimplementować niezaznaczonego operatora, na przykład Subtraction(TSelf, TOther).
Interfejsy funkcji
Interfejsy funkcji definiują typowe interfejsy API matematyczne, które mają zastosowanie szerzej niż do określonego interfejsu liczbowego. Wszystkie te interfejsy są implementowane przez IFloatingPointIeee754<TSelf>program i mogą zostać zaimplementowane przez inne odpowiednie typy w przyszłości.
Nazwa interfejsu | opis |
---|---|
IExponentialFunctions<TSelf> | Uwidacznia funkcje wykładnicze obsługujące e^x funkcje , , e^x - 1 , 2^x , 2^x - 1 10^x , i 10^x - 1 . |
IHyperbolicFunctions<TSelf> | Uwidacznia funkcje hiperboliczne obsługujące acosh(x) funkcje , , asinh(x) , atanh(x) cosh(x) , sinh(x) i tanh(x) . |
ILogarithmicFunctions<TSelf> | Uwidacznia funkcje logarytmicznych obsługujące ln(x) funkcje , , ln(x + 1) , log2(x) log2(x + 1) , log10(x) , i log10(x + 1) . |
IPowerFunctions<TSelf> | Uwidacznia funkcje zasilania obsługujące funkcję x^y . |
IRootFunctions<TSelf> | Uwidacznia funkcje główne obsługujące cbrt(x) i sqrt(x) . |
ITrigonometricFunctions<TSelf> | Udostępnia funkcje trygonometryczne obsługujące acos(x) funkcje , , asin(x) , atan(x) , cos(x) , sin(x) i tan(x) . |
Interfejsy analizowania i formatowania
Analizowanie i formatowanie to podstawowe pojęcia w programowaniu. Są one często używane podczas konwertowania danych wejściowych użytkownika na dany typ lub wyświetlania typu użytkownikowi. Te interfejsy znajdują się w System przestrzeni nazw.
Nazwa interfejsu | opis |
---|---|
IParsable<TSelf> | Uwidacznia obsługę poleceń T.Parse(string, IFormatProvider) i T.TryParse(string, IFormatProvider, out TSelf) . |
ISpanParsable<TSelf> | Uwidacznia obsługę poleceń T.Parse(ReadOnlySpan<char>, IFormatProvider) i T.TryParse(ReadOnlySpan<char>, IFormatProvider, out TSelf) . |
IFormattable1 | Uwidacznia obsługę programu value.ToString(string, IFormatProvider) . |
ISpanFormattable1 | Uwidacznia obsługę programu value.TryFormat(Span<char>, out int, ReadOnlySpan<char>, IFormatProvider) . |
1Ten interfejs nie jest nowy ani nie jest ogólny. Jednak jest on implementowany przez wszystkie typy liczb i reprezentuje odwrotną operację IParsable
.
Na przykład poniższy program przyjmuje dwie liczby jako dane wejściowe, odczytując je z konsoli przy użyciu metody ogólnej, w której parametr typu jest ograniczony do IParsable<TSelf>. Oblicza średnią przy użyciu metody ogólnej, w której parametry typu dla wartości wejściowych i wynikowych są ograniczone do INumber<TSelf>wartości , a następnie wyświetla wynik w konsoli.
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
*/