Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
.NET 7 представляет новые универсальные интерфейсы, связанные с математикой, в библиотеке базовых классов. Наличие этих интерфейсов означает, что параметр типа обобщенного типа или метода может быть "похожим на число". Кроме того, C# 11 и более поздних версий позволяет определять static virtual
элементы интерфейса. Так как операторы должны быть объявлены как static
, эта новая функция C# позволяет объявлять операторы в новых интерфейсах для типов, таких как число.
Вместе эти инновации позволяют выполнять математические операции универсально, т. е. не зная точного типа, с которым вы работаете. Например, если вы хотите написать метод, добавляющий два числа, ранее пришлось добавить перегрузку метода для каждого типа (например, static int Add(int first, int second)
и static float Add(float first, float second)
). Теперь вы можете написать единый универсальный метод, в котором параметр типа ограничен типом, похожим на числовой. Рассмотрим пример.
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, потому что все они были обновлены для реализации INumber<TSelf> в .NET 7.
Авторы библиотеки получают большую выгоду от универсальных математических интерфейсов, так как они могут упростить базу кода, удаляя избыточные перегрузки. Другие разработчики будут получать косвенную выгоду, поскольку API, которые они потребляют, могут начать поддерживать больше типов.
Интерфейсы
Интерфейсы были разработаны достаточно детально, чтобы пользователи могли создавать собственные интерфейсы на их основе, а также быть достаточно понятными, чтобы их было легко использовать. В этой степени существует несколько основных числовых интерфейсов, с которыми большинство пользователей будут взаимодействовать, например INumber<TSelf> и IBinaryInteger<TSelf>. Более подробные интерфейсы, такие как IAdditionOperators<TSelf,TOther,TResult> и ITrigonometricFunctions<TSelf>, поддерживают эти типы и доступны разработчикам, которые определяют собственные числовые интерфейсы, относящиеся к домену.
Числовые интерфейсы
В этом разделе описываются интерфейсы в System.Numerics, которые описывают типы, похожие на числа, и функции, доступные для них.
Имя интерфейса | Описание |
---|---|
IBinaryFloatingPointIeee754<TSelf> | Обеспечивает общие API для типов с плавающей точкой, реализующих стандарт IEEE 7541. |
IBinaryInteger<TSelf> | Предоставляет API, общие для двоичных целых чисел2. |
IBinaryNumber<TSelf> | Предоставляет API-интерфейсы, общие для двоичных чисел. |
IFloatingPoint<TSelf> | Предоставляет API, характерные для типов данных с плавающей точкой. |
IFloatingPointIeee754<TSelf> | Предоставляет API, общие для чисел с плавающей запятой, реализующих стандарт IEEE 754. |
INumber<TSelf> | Предоставляет интерфейсы API, общие для сопоставимых типов чисел (фактически "область действительных чисел"). |
INumberBase<TSelf> | Предоставляет интерфейсы API, общие для всех типов чисел (фактически домен комплексных чисел). |
ISignedNumber<TSelf> | Предоставляет API, общие для всех знаковых типов чисел (например, концепции NegativeOne ). |
IUnsignedNumber<TSelf> | Предоставляет интерфейсы API, общие для всех типов неподписанных чисел. |
IAdditiveIdentity<TSelf,TResult> | Раскрывает концепцию (x + T.AdditiveIdentity) == x . |
IMinMaxValue<TSelf> | Раскрывает концепцию T.MinValue и T.MaxValue . |
IMultiplicativeIdentity<TSelf,TResult> | Раскрывает концепцию (x * T.MultiplicativeIdentity) == x . |
1Двоичные типы с плавающей запятой (Doubledouble
), Halfи Single (float
).
2Двоичные целочисленные типы: Byte (byte
), Int16 (short
), Int32 (int
), Int64 (long
), Int128, IntPtr (nint
), SByte (sbyte
), UInt16 (ushort
), UInt32 (uint
), UInt64 (ulong
), UInt128, и UIntPtr (nuint
).
Интерфейс, который вы, скорее всего, будете использовать напрямую — это INumber<TSelf>, который приблизительно соответствует реальному числу. Если тип реализует этот интерфейс, это означает, что значение имеет знак ( unsigned
включает типы, которые считаются положительными) и можно сравнить с другими значениями того же типа.
INumberBase<TSelf> предоставляет более сложные понятия, такие как сложные и мнимые числа, например квадратный корень отрицательного числа. Другие интерфейсы, такие как IFloatingPointIeee754<TSelf>, были созданы потому, что не все операции имеют смысл для всех типов чисел—например, нахождение целой части числа имеет смысл только для типов с плавающей запятой. В библиотеке базовых классов .NET тип Double с плавающей запятой реализует IFloatingPointIeee754<TSelf> , но Int32 не выполняет.
Некоторые интерфейсы также реализуются различными другими типами, включая Char, DateOnly, DateTime, DateTimeOffset, Decimal, Guid, TimeOnly, и TimeSpan.
В следующей таблице показаны некоторые основные 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 |
Возвращает значение, представляющее число Эйлера для типа. |
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 |
Создает значение, выбрасывая OverflowException исключение, если входные данные не могут поместиться.1 | |
CreateSaturating |
Создает значение, ограничивая до T.MinValue или T.MaxValue если входные данные не подходят.1 |
|
CreateTruncating |
Создает значение из другого значения, обтекая вокруг, если входные данные не могут соответствовать. 1 | |
IsComplexNumber |
Возвращает значение true, если значение имеет ненульную реальную часть и ненульную мнимую часть. | |
IsEvenInteger |
Возвращает значение true, если значение является даже целым числом. 2.0 возвращает true , а 2.2 возвращает false . |
|
IsFinite |
Возвращает значение true, если значение не бесконечно, а не NaN . |
|
IsImaginaryNumber |
Возвращает true, если значение имеет нулевую реальную часть. Это означает, что 0 мнимый, а 1 + 1i нет. |
|
IsInfinity |
Возвращает значение true, если значение представляет бесконечность. | |
IsInteger |
Возвращает значение true, если значение является целым числом. Версии 2.0 и 3.0 возвращают true , а 2.2 и 3.1 возвращают false . |
|
IsNaN |
Возвращает значение true, если значение представляет NaN . |
|
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, например float
и , так как они имеют специальные значения double
, PositiveInfinity
и NegativeInfinity
NaN
. Все три Create*
API ведут себя как CreateSaturating
. Кроме того, в то время как MinValue
и MaxValue
представляют наибольшее отрицательное и положительное "нормальное" число, фактические минимальные и максимальные значения — это NegativeInfinity
и PositiveInfinity
, поэтому они зажимаются до этих значений вместо этого.
Интерфейсы операторов
Интерфейсы операторов соответствуют различным операторам, доступным для языка C#.
- Они явно не объединяют такие операции, как умножение и деление, так как это не правильно для всех типов. Например,
Matrix4x4 * Matrix4x4
является допустимым, ноMatrix4x4 / Matrix4x4
недопустимым. - Обычно они позволяют типам входных и результирующих данных отличаться для сценариев поддержки, таких как деление двух целых чисел для получения
double
, например,3 / 2 = 1.5
или вычисления среднего значения набора целых чисел.
Имя интерфейса | Определенные операторы |
---|---|
IAdditionOperators<TSelf,TOther,TResult> | x + y |
IBitwiseOperators<TSelf,TOther,TResult> |
x & y , 'x | y', x ^ y и ~x |
IComparisonOperators<TSelf,TOther,TResult> |
x < y , x > y , x <= y и x >= y |
IDecrementOperators<TSelf> |
--x и x-- . |
IDivisionOperators<TSelf,TOther,TResult> | x / y |
IEqualityOperators<TSelf,TOther,TResult> |
x == y и x != y . |
IIncrementOperators<TSelf> |
++x и x++ . |
IModulusOperators<TSelf,TOther,TResult> | x % y |
IMultiplyOperators<TSelf,TOther,TResult> | x * y |
IShiftOperators<TSelf,TOther,TResult> |
x << y и x >> y . |
ISubtractionOperators<TSelf,TOther,TResult> | x - y |
IUnaryNegationOperators<TSelf,TResult> | -x |
IUnaryPlusOperators<TSelf,TResult> | +x |
Замечание
Некоторые интерфейсы определяют проверяемый оператор в дополнение к обычному оператору без флажка. Проверенные операторы вызываются в проверяемых контекстах и позволяют определяемого пользователем типа определять поведение переполнения. Если вы реализуете оператор с проверкой, например, CheckedSubtraction(TSelf, TOther), необходимо также реализовать оператор без проверки, например, Subtraction(TSelf, TOther).
Интерфейсы функций
Интерфейсы функций определяют общие математические API, которые применяются более широко, чем конкретный числовой интерфейс. IFloatingPointIeee754<TSelf> реализует все эти интерфейсы, и в будущем они могут быть реализованы другими соответствующими типами.
Имя интерфейса | Описание |
---|---|
IExponentialFunctions<TSelf> | Предоставляет экспоненциальные функции, поддерживающие e^x , e^x - 1 , 2^x , 2^x - 1 , 10^x и 10^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) . |
IFormattable 1 | Предоставляет поддержку value.ToString(string, IFormatProvider) . |
ISpanFormattable 1 | Предоставляет поддержку value.TryFormat(Span<char>, out int, ReadOnlySpan<char>, IFormatProvider) . |
1Этот интерфейс не является новым и универсальным. Однако он реализуется всеми типами чисел и представляет обратную операцию IParsable
.
Например, следующая программа принимает два числа в качестве входных данных, считывая их из консоли с помощью универсального метода, в котором параметр типа ограничен.IParsable<TSelf> Он вычисляет среднее значение с помощью универсального метода, в котором параметры типа для входных и результирующих значений ограничены INumber<TSelf>, а затем отображаются результаты в консоли.
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
*/