Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
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 generycznego lub metody na "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ę. 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. Metody można użyć z dowolnym wbudowanym typem liczbowym platformy .NET, ponieważ wszystkie zostały zaktualizowane do implementacji INumber<TSelf> w .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ć na ich podstawie własne interfejsy, a jednocześnie są wystarczająco dostosowane, aby były łatwe w użyciu. 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 w System.Numerics, które opisują typy podobne do liczb oraz funkcjonalność, która jest dla nich dostępna.
Nazwa interfejsu | Opis |
---|---|
IBinaryFloatingPointIeee754<TSelf> | Uwidacznia interfejsy API wspólne dla binarnych typów zmiennoprzecinkowych1 , które implementują standard IEEE 754. |
IBinaryInteger<TSelf> | Uwidacznia interfejsy API wspólne dla liczb binarnych2. |
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> | Udostępnia interfejsy API wspólne dla wszystkich typów liczb ze znakiem (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 są Double (double
), Half, i Single (float
).
2Typy liczb całkowitych binarnych to Byte (byte
), Int16 (short
), Int32 (int
), Int64 (long
), Int128, IntPtr (nint
), SByte (sbyte
), UInt16 (ushort
), UInt32 (uint
), UInt64 (ulong
), UInt128 i 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ść posiada znak (w tym obejmuje to typy unsigned
, które są uważane za dodatnie) i może być porównywana 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 zmiennoprzecinkowy implementuje IFloatingPointIeee754<TSelf>, ale Int32 nie.
Kilka interfejsów jest również implementowanych przez różne inne typy, w tym Char, DateOnly, DateTime, DateTimeOffset, Decimal, Guid, TimeOnly i TimeSpan.
W poniższej tabeli przedstawiono niektóre kluczowe interfejsy API dostępne w każdym interfejsie.
Interfejs | Nazwa interfejsu API | Opis |
---|---|---|
IBinaryInteger<TSelf> | DivRem |
Oblicza jednocześnie iloraz i resztę. |
LeadingZeroCount |
Zlicza liczbę bitów zer wiodących w reprezentacji binarnej. | |
PopCount |
Zlicza liczbę bitów ustawionych w reprezentacji binarnej. | |
RotateLeft |
Obraca bity w lewo, nazywane także cyrkulacyjnym przesunięciem w lewo. | |
RotateRight |
Obraca bity w prawo, czasami nazywane również okrągłym przesunięciem w prawo. | |
TrailingZeroCount |
Zlicza liczbę zerowych bitów końcowych 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ą możliwą wartość większą niż zero, jaka może być reprezentowana przez dany typ. | |
NaN |
Pobiera wartość, która reprezentuje NaN dla danego typu. |
|
NegativeInfinity |
Pobiera wartość, która reprezentuje -Infinity dla danego typu. |
|
NegativeZero |
Pobiera wartość, która reprezentuje -Zero dla danego typu. |
|
Pi |
Pobiera wartość, która reprezentuje Pi dla danego typu. |
|
PositiveInfinity |
Pobiera wartość, która reprezentuje +Infinity dla danego typu. |
|
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 , jeśli którykolwiek 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 , gdy którykolwiek z danych wejściowych wynosi NaN . |
|
MinNumber |
Zwraca mniejszą z dwóch wartości, zwracając liczbę, jeśli jedno dane wejściowe to NaN . |
|
Sign |
Zwraca -1 dla wartości ujemnych, 0 dla zera i +1 dla wartości dodatnich. | |
INumberBase<TSelf> | One |
Pobiera wartość 1 dla typu. |
Radix |
Pobiera podstawę (radix) dla typu. Int32 zwraca wartość 2. Decimal Zwraca wartość 10. | |
Zero |
Pobiera wartość 0 dla typu. | |
CreateChecked |
Tworzy wartość, zgłaszając wyjątek OverflowException, jeśli dane wejściowe nie pasują.1 | |
CreateSaturating |
Tworzy wartość, ogranicza do T.MinValue lub T.MaxValue jeśli wejście nie może 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 true, jeśli część rzeczywista wartości jest równa zero. To oznacza, że 0 jest wyimaginowany, a 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 true, jeśli wartość reprezentuje NaN . |
|
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 "true", jeśli wartość reprezentuje zero. Obejmuje to wartości 0, +0.0 i -0.0. | |
MaxMagnitude |
Zwraca wartość o większej wartości bezwzględnej, zwracając NaN , jeśli którekolwiek z danych wejściowych 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 lepiej zrozumieć zachowanie trzech Create*
metod, rozważ poniższe przykłady.
Przykład, gdy dana wartość jest zbyt duża:
-
byte.CreateChecked(384)
zgłosi 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)
zgłosi OverflowException. -
byte.CreateSaturating(-384)
Zwraca wartość 0, ponieważ -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 pozwalają na różnice między typami danych wejściowych i wynikowych, aby obsługiwać scenariusze takie jak dzielenie dwóch liczb całkowitych do uzyskania wartości
double
, 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 / Notatka
Niektóre interfejsy definiują operator sprawdzany oprócz zwykłego operatora niesprawdzanego. Sprawdzone operatory są wywoływane w kontekstach sprawdzania i pozwalają typowi zdefiniowanemu przez użytkownika określić zachowanie przy przepełnieniu. Jeśli zaimplementujesz operator z kontrolą, na przykład CheckedSubtraction(TSelf, TOther), musisz również zaimplementować operator bez kontroli, 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> i mogą zostać zaimplementowane przez inne odpowiednie typy w przyszłości.
Nazwa interfejsu | Opis |
---|---|
IExponentialFunctions<TSelf> | Udostępnia funkcje wykładnicze obsługujące e^x , e^x - 1 , 2^x , 2^x - 1 , 10^x i 10^x - 1 . |
IHyperbolicFunctions<TSelf> | Uwidacznia funkcje hiperboliczne obsługujące acosh(x) , asinh(x) , atanh(x) , cosh(x) , sinh(x) i tanh(x) . |
ILogarithmicFunctions<TSelf> | Udostępnia funkcje logarytmiczne obsługujące ln(x) , 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) , 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> | Udostępnia wsparcie dla T.Parse(string, IFormatProvider) i T.TryParse(string, IFormatProvider, out TSelf) . |
ISpanParsable<TSelf> | Udostępnia wsparcie dla T.Parse(ReadOnlySpan<char>, IFormatProvider) i T.TryParse(ReadOnlySpan<char>, IFormatProvider, out TSelf) . |
IFormattable 1 | Uwidacznia obsługę programu value.ToString(string, IFormatProvider) . |
ISpanFormattable 1 | 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 typów dla wartości wejściowych i wynikowych są ograniczone do INumber<TSelf>, a następnie wynik jest wyświetlany 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
*/