.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의 기본 제공 숫자 형식과 함께 사용할 수 있으며, 이는 모두 .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> | 모든 부호 있는 숫자 유형(예: NegativeOne 개념)에 공통적인 API를 제공합니다. |
| IUnsignedNumber<TSelf> | 서명되지 않은 모든 숫자 형식에 공통적인 API를 노출합니다. |
| IAdditiveIdentity<TSelf,TResult> |
(x + T.AdditiveIdentity) == x 개념을 설명합니다. |
| IMinMaxValue<TSelf> |
T.MinValue 및 T.MaxValue의 개념을 드러냅니다. |
| IMultiplicativeIdentity<TSelf,TResult> |
(x * T.MultiplicativeIdentity) == x 개념을 설명합니다. |
1이진 부동 소수점 형식은 Double(double), 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 |
이진 표현에서 선행 0비트 수를 계산합니다. | |
PopCount |
이진 표현의 집합 비트 수를 계산합니다. | |
RotateLeft |
비트를 왼쪽으로 회전하는데, 이는 원형 왼쪽 시프트라고도 합니다. | |
RotateRight |
비트를 오른쪽으로 회전시키며, 이를 원형 우측 시프트라고도 합니다. | |
TrailingZeroCount |
이진 표현의 후행 0비트 수를 계산합니다. | |
| IFloatingPoint<TSelf> | Ceiling |
값을 양수 무한대로 반올림합니다. +4.5는 +5가 되고 -4.5는 -4가 됩니다. |
Floor |
값을 음의 무한대로 반올림합니다. +4.5는 +4가 되고 -4.5는 -5가 됩니다. | |
Round |
지정된 반올림 모드를 사용하여 값을 반올림합니다. | |
Truncate |
값을 0으로 반올림합니다. +4.5는 +4가 되고 -4.5는 -4가 됩니다. | |
| IFloatingPointIeee754<TSelf> | E |
형식에 대한 Euler의 번호를 나타내는 값을 가져옵니다. |
Epsilon |
형식에 대해 0보다 큰 가장 작은 표현 가능 값을 가져옵니다. | |
NaN |
형식을 나타내는 NaN 값을 가져옵니다. |
|
NegativeInfinity |
형식을 나타내는 -Infinity 값을 가져옵니다. |
|
NegativeZero |
형식을 나타내는 -Zero 값을 가져옵니다. |
|
Pi |
형식을 나타내는 Pi 값을 가져옵니다. |
|
PositiveInfinity |
형식을 나타내는 +Infinity 값을 가져옵니다. |
|
Tau |
형식을 나타내는 Tau 값(2 * Pi)을 가져옵니다. |
|
| (기타) | (함수 인터페이스 아래에 나열된 전체 인터페이스 집합을 구현합니다.) | |
| INumber<TSelf> | Clamp |
값을 지정된 최소값 및 최대값보다 작지 않은 값으로 제한합니다. |
CopySign |
지정된 값의 부호를 지정된 다른 값과 동일하게 설정합니다. | |
Max |
두 값 중 더 큰 값을 반환하고 NaN 입력이 두 값 중 하나일 경우 반환합니다 NaN. |
|
MaxNumber |
두 값 중 더 큰 값을 반환하고 입력이 1 NaN개인 경우 숫자를 반환합니다. |
|
Min |
두 값 중 더 작은 값을 반환하고 입력 중 하나가 NaN 이면 반환합니다 NaN. |
|
MinNumber |
두 값 중 더 작은 값을 반환하고 입력 NaN이 1개인 경우 숫자를 반환합니다. |
|
Sign |
음수 값에 대한 -1, 0의 경우 0, 양수 값의 경우 +1을 반환합니다. | |
| INumberBase<TSelf> | One |
형식의 값 1을 가져옵니다. |
Radix |
형식의 radix 또는 base를 가져옵니다. Int32 는 2를 반환합니다. Decimal 10을 반환합니다. | |
Zero |
형식의 값 0을 가져옵니다. | |
CreateChecked |
입력이 맞지 않을 경우 OverflowException을(를) 던져 값을 생성합니다.1 | |
CreateSaturating |
입력이 맞지 않을 경우 T.MinValue 또는 T.MaxValue로 고정하여 값을 만듭니다.1 |
|
CreateTruncating |
입력이 맞지 않는 경우 래핑하여 다른 값에서 값을 만듭니다. 1 | |
IsComplexNumber |
값에 0이 아닌 실제 부분과 0이 아닌 허수 부분이 있으면 true를 반환합니다. | |
IsEvenInteger |
값이 짝수이면 true를 반환합니다. 2.0은 true을 반환하고, 2.2는 false을 반환합니다. |
|
IsFinite |
값이 무한이 아닌 NaN경우 true를 반환합니다. |
|
IsImaginaryNumber |
값에 실제 부분이 0이면 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 |
값에 허수 부분이 0이면 true를 반환합니다. 즉, 0은 모든 INumber<T> 형식과 마찬가지로 실제입니다. |
|
IsZero |
값이 0을 나타내는 경우 true를 반환합니다. 여기에는 0, +0.0 및 -0.0이 포함됩니다. | |
MaxMagnitude |
절대값의 크기를 비교하여 더 큰 값을 반환하며, 만약 어느 한 입력이 NaN라면 NaN을 반환합니다. |
|
MaxMagnitudeNumber |
절대값이 더 큰 값을 반환하고 입력이 NaN1인 경우 숫자를 반환합니다. |
|
MinMagnitude |
입력 값 중 하나가 NaN일 경우 NaN을 반환하며, 그렇지 않으면 절대값이 더 작은 값을 반환합니다. |
|
MinMagnitudeNumber |
절대값이 더 작은 값을 반환하고 입력 NaN이 1인 경우 숫자를 반환합니다. |
|
| ISignedNumber<TSelf> | NegativeOne |
형식에 대한 -1 값을 가져옵니다. |
1세 Create* 가지 메서드의 동작을 이해하려면 다음 예제를 고려하세요.
너무 큰 값이 지정된 경우의 예:
-
byte.CreateChecked(384)이(가) OverflowException을(를) 발생시킵니다. -
byte.CreateSaturating(384)는 384가 255보다 Byte.MaxValue 크므로 255를 반환합니다. -
byte.CreateTruncating(384)는 가장 낮은 8비트를 사용하므로 128을 반환합니다(384에는 16진수 표현0x0180이 있고 가장 낮은 8비트는0x80128).
너무 작은 값이 지정된 경우의 예:
-
byte.CreateChecked(-384)이(가) OverflowException을(를) 발생시킵니다. -
byte.CreateSaturating(-384)는 -384 (0)보다 Byte.MinValue 작기 때문에 0을 반환합니다. -
byte.CreateTruncating(-384)는 가장 낮은 8비트를 사용하므로 128을 반환합니다(384에는 16진수 표현0xFE80이 있고 가장 낮은 8비트는0x80128).
또한 Create* 메서드는 float 및 double와 같은 IEEE 754 부동 소수점 형식에 대해 PositiveInfinity, NegativeInfinity, NaN 등의 특수 값을 사용할 때 몇 가지 특별한 고려 사항이 있습니다. 모든 세 개의 Create* API는 CreateSaturating로 동작합니다. 또한 MinValue 및 MaxValue는 가장 큰 음수/양수 "표준" 숫자를 나타내지만, 실제 최소값과 최대값은 NegativeInfinity 및 PositiveInfinity이므로, 대신 이 값으로 고정됩니다.
연산자 인터페이스
연산자 인터페이스는 C# 언어에서 사용할 수 있는 다양한 연산자에 해당합니다.
- 모든 형식에 대해 올바르지 않으므로 곱하기 및 나누기와 같은 작업을 명시적으로 페어링하지 않습니다. 예를 들어
Matrix4x4 * Matrix4x4유효하지만Matrix4x4 / Matrix4x4유효하지는 않습니다. - 일반적으로 입력 및 결과 형식은 두 정수로 나누어 정
double3 / 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
*/
참고하십시오
.NET