Obecná matematika

.NET 7 zavádí nová obecná rozhraní související s matematikou do knihovny základních tříd. Dostupnost těchto rozhraní znamená, že můžete omezit parametr typu obecného typu nebo metody tak, aby byl "číslo-like". Kromě toho jazyk C# 11 a novější umožňuje definovat static virtual členy rozhraní. Vzhledem k tomu, že operátory musí být deklarovány jako static, tato nová funkce jazyka C# umožňuje deklarovat operátory v nových rozhraních pro typy podobné číslům.

Tyto inovace vám společně umožňují provádět matematické operace obecně – to znamená, že nemusíte znát přesný typ, se kterým pracujete. Pokud byste například chtěli napsat metodu, která sečte dvě čísla, museli jste dříve přidat přetížení metody pro každý typ (například static int Add(int first, int second) a static float Add(float first, float second)). Teď můžete napsat jednu obecnou metodu, kde je parametr typu omezený na typ podobný číslu. Příklad:

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

V této metodě je parametr T typu omezen na typ, který implementuje nové INumber<TSelf> rozhraní. INumber<TSelf> implementuje IAdditionOperators<TSelf,TOther,TResult> rozhraní, které obsahuje operátor +. To umožňuje metodě obecně sčítat dvě čísla. Metodu lze použít s libovolnou z . Integrované číselné typy net, protože všechny byly aktualizovány tak, aby se implementovaly INumber<TSelf> v .NET 7.

Autoři knihoven budou mít největší prospěch z obecných matematických rozhraní, protože můžou zjednodušit základ kódu odebráním "redundantních" přetížení. Jiní vývojáři budou mít nepřímo výhodu, protože rozhraní API, která využívají, mohou začít podporovat více typů.

Rozhraní

Rozhraní byla navržena tak, aby byla dostatečně jemně odstupňovaná, aby uživatelé mohli definovat svá vlastní rozhraní navrchu a zároveň byla dostatečně podrobná, aby byla snadno použitelná. V takovém případě existuje několik základních číselných rozhraní, se kterými bude většina uživatelů pracovat, například INumber<TSelf> a IBinaryInteger<TSelf>. Podrobnější rozhraní, například IAdditionOperators<TSelf,TOther,TResult> a ITrigonometricFunctions<TSelf>, podporují tyto typy a jsou k dispozici pro vývojáře, kteří definují vlastní číselná rozhraní specifická pro doménu.

Číselná rozhraní

Tato část popisuje rozhraní, která System.Numerics popisují typy podobné číslům a funkce, které jsou jim k dispozici.

Název rozhraní Popis
IBinaryFloatingPointIeee754<TSelf> Zveřejňuje rozhraní API společná pro binární typys plovoucí desetinnou čárkou 1 , které implementují standard IEEE 754.
IBinaryInteger<TSelf> Zveřejňuje rozhraní API společná pro binární celá čísla2.
IBinaryNumber<TSelf> Zveřejňuje rozhraní API společná pro binární čísla.
IFloatingPoint<TSelf> Zveřejňuje rozhraní API společná pro typy s plovoucí desetinnou čárkou.
IFloatingPointIeee754<TSelf> Zveřejňuje rozhraní API společná pro typy s plovoucí desetinnou čárkou, které implementují standard IEEE 754.
INumber<TSelf> Zveřejňuje rozhraní API společná pro srovnatelné typy čísel (v podstatě "reálná" číselná doména).
INumberBase<TSelf> Zveřejňuje rozhraní API společná pro všechny typy čísel (v podstatě "složitá" číselná doména).
ISignedNumber<TSelf> Zveřejňuje rozhraní API společná pro všechny typy podepsaných čísel (například koncept ).NegativeOne
IUnsignedNumber<TSelf> Zveřejňuje rozhraní API společná pro všechny typy čísel bez znaménka.
IAdditiveIdentity<TSelf,TResult> Zpřístupňuje koncept .(x + T.AdditiveIdentity) == x
IMinMaxValue<TSelf> Zveřejňuje koncept T.MinValue a T.MaxValue.
IMultiplicativeIdentity<TSelf,TResult> Zpřístupňuje koncept .(x * T.MultiplicativeIdentity) == x

1 Binární typy s plovoucí desetinou čárkou jsou Double (double), Halfa Single (float).

2Binární celočíselné typy jsou Byte (byte), Int16 (short), Int32 (int), Int64 (long), Int128, IntPtr (nint), SByte (sbyte), UInt16 (ushort), UInt32 (uint), (), UInt64 a UInt128ulongUIntPtr (nuint).

Rozhraní, které budete pravděpodobně používat přímo, je INumber<TSelf>, což zhruba odpovídá skutečnému číslu. Pokud typ implementuje toto rozhraní, znamená to, že hodnota má znaménko (to zahrnuje unsigned typy, které jsou považovány za kladné) a lze je porovnat s jinými hodnotami stejného typu. INumberBase<TSelf> poskytuje pokročilejší koncepty, jako jsou složitá a imaginární čísla, například druhá odmocnina záporného čísla. Jiná rozhraní, například IFloatingPointIeee754<TSelf>, byla vytvořena, protože ne všechny operace mají smysl pro všechny typy čísel – například výpočet podlahy čísla dává smysl pouze pro typy s plovoucí desetinou čárkou. V knihovně základních tříd .NET implementuje IFloatingPointIeee754<TSelf> typ Double s plovoucí desetinou čárkou, ale Int32 ne.

Několik rozhraní jsou také implementovány různými jinými typy, včetně Char, DateOnly, DateTime, , DateTimeOffset, Decimal, , GuidTimeOnlya TimeSpan.

Následující tabulka uvádí některá základní rozhraní API vystavená jednotlivými rozhraními.

Rozhraní Název rozhraní API Popis
IBinaryInteger<TSelf> DivRem Vypočítá podíl a zbytek současně.
LeadingZeroCount Spočítá počet počátečních nul bitů v binární reprezentaci.
PopCount Spočítá počet bitů sady v binární reprezentaci.
RotateLeft Obměňuje bity doleva, někdy se také označuje jako kruhový levý posun.
RotateRight Obměňuje bity doprava, někdy se označuje také jako kruhový pravý posun.
TrailingZeroCount Spočítá počet koncových nul bitů v binární reprezentaci.
IFloatingPoint<TSelf> Ceiling Zaokrouhlí hodnotu na kladné nekonečno. +4,5 se změní na +5 a -4,5 se změní na -4.
Floor Zaokrouhlí hodnotu na záporné nekonečno. +4,5 se změní na +4 a -4,5 se změní na -5.
Round Zaokrouhlí hodnotu pomocí zadaného režimu zaokrouhlování.
Truncate Zaokrouhlí hodnotu na nulu. +4,5 se změní na +4 a -4,5 se změní na -4.
IFloatingPointIeee754<TSelf> E Získá hodnotu představující Eulerovo číslo pro typ.
Epsilon Získá nejmenší reprezentovatelnou hodnotu, která je pro typ větší než nula.
NaN Získá hodnotu představující NaN typ.
NegativeInfinity Získá hodnotu představující -Infinity typ.
NegativeZero Získá hodnotu představující -Zero typ.
Pi Získá hodnotu představující Pi typ.
PositiveInfinity Získá hodnotu představující +Infinity typ.
Tau Získá hodnotu představující Tau (2 * Pi) pro typ.
(Jiné) (Implementuje úplnou sadu rozhraní uvedených v části Rozhraní funkcí.)
INumber<TSelf> Clamp Omezí hodnotu na maximálně a ne méně než zadaná minimální a maximální hodnota.
CopySign Nastaví znaménko zadané hodnoty na stejnou jako jiná zadaná hodnota.
Max Vrátí větší ze dvou hodnot, které NaN vrátí, pokud je některý ze vstupů NaN.
MaxNumber Vrátí větší ze dvou hodnot a vrátí číslo, pokud je NaNjedním vstupem .
Min Vrátí menší ze dvou hodnot, které NaN vrátí, pokud je NaNněkterý ze vstupů .
MinNumber Vrátí menší ze dvou hodnot a vrátí číslo, pokud je NaNjedním vstupem .
Sign Vrátí hodnotu -1 pro záporné hodnoty, 0 pro nulu a +1 pro kladné hodnoty.
INumberBase<TSelf> One Získá hodnotu 1 pro typ.
Radix Získá radix nebo základ pro typ. Int32 vrátí hodnotu 2. Decimal vrátí 10.
Zero Získá hodnotu 0 pro typ.
CreateChecked Vytvoří hodnotu, která OverflowException vyvolá výjimku, pokud se vstup nevejde.1
CreateSaturating Vytvoří hodnotu, upnutí nebo T.MinValueT.MaxValue pokud se vstup nevejde.1
CreateTruncating Vytvoří hodnotu z jiné hodnoty, která se obtéká kolem, pokud se vstup nevejde.1
IsComplexNumber Vrátí hodnotu true, pokud má hodnota nenulovou reálnou část a nenulovou imaginární část.
IsEvenInteger Vrátí hodnotu true, pokud je hodnota sudým celé číslo. Vrátí hodnotu 2,0 truea vrátí falsehodnotu 2,2 .
IsFinite Vrátí hodnotu true, pokud hodnota není nekonečná, a ne NaN.
IsImaginaryNumber Vrátí hodnotu true, pokud má hodnota nulovou reálnou část. To znamená 0 , že je imaginární a 1 + 1i není.
IsInfinity Vrátí hodnotu true, pokud hodnota představuje nekonečno.
IsInteger Vrátí hodnotu true, pokud je hodnota celé číslo. 2.0 a 3.0 return truea 2.2 a 3.1 return false.
IsNaN Vrátí hodnotu true, pokud hodnota představuje NaN.
IsNegative Vrátí hodnotu true, pokud je hodnota záporná. To zahrnuje -0.0.
IsPositive Vrátí hodnotu true, pokud je hodnota kladná. To zahrnuje 0 a +0,0.
IsRealNumber Vrátí hodnotu true, pokud má hodnota nulovou imaginární část. To znamená, že hodnota 0 je skutečná jako všechny INumber<T> typy.
IsZero Vrátí hodnotu true, pokud hodnota představuje nulu. To zahrnuje 0, +0,0 a -0,0.
MaxMagnitude Vrátí hodnotu s větší absolutní hodnotou, která NaN vrátí, pokud je NaNněkterý ze vstupů .
MaxMagnitudeNumber Vrátí hodnotu s větší absolutní hodnotou, která vrátí číslo, pokud je NaNjedním vstupem .
MinMagnitude Vrátí hodnotu s menší absolutní hodnotou, která NaN vrátí, pokud je NaNněkterý ze vstupů .
MinMagnitudeNumber Vrátí hodnotu s menší absolutní hodnotou, která vrátí číslo, pokud je NaNjedním vstupem .
ISignedNumber<TSelf> NegativeOne Získá hodnotu -1 pro typ.

1,abyste pochopili chování těchto tří Create* metod, zvažte následující příklady.

Příklad při zadání hodnoty, která je příliš velká:

  • byte.CreateChecked(384)vyhodí .OverflowException
  • byte.CreateSaturating(384) vrátí hodnotu 255, protože 384 je větší než Byte.MaxValue (což je 255).
  • byte.CreateTruncating(384) vrátí 128, protože přebírá nejnižší 8 bitů (384 má šestnáctkové vyjádření 0x0180a nejnižší 8 bitů je , což je 0x80128).

Příklad při zadání hodnoty, která je příliš malá:

  • byte.CreateChecked(-384)vyhodí .OverflowException
  • byte.CreateSaturating(-384) vrátí hodnotu 0, protože -384 je menší než Byte.MinValue (což je 0).
  • byte.CreateTruncating(-384) vrátí 128, protože přebírá nejnižší 8 bitů (384 má šestnáctkové vyjádření 0xFE80a nejnižší 8 bitů je , což je 0x80128).

Tyto Create* metody mají také některé zvláštní aspekty pro typy s plovoucí desetinou čárkou IEEE 754, například float a double, protože mají zvláštní hodnoty PositiveInfinity, NegativeInfinitya NaN. Všechna tři Create* rozhraní API se chovají jako CreateSaturating. I když MinValue a MaxValue představuje největší záporné/kladné "normální" číslo, skutečné minimum a maximální hodnoty jsou NegativeInfinity a PositiveInfinity, takže se uchytnou na tyto hodnoty.

Rozhraní operátorů

Rozhraní operátorů odpovídají různým operátorům dostupným v jazyce C#.

  • Explicitně nedají spárovat operace, jako je násobení a dělení, protože to není správné pro všechny typy. Je například Matrix4x4 * Matrix4x4 platný, ale Matrix4x4 / Matrix4x4 není platný.
  • Obvykle umožňují, aby se vstupní typy a typy výsledků lišily, aby podporovaly scénáře, jako jsou rozdělení dvou celých čísel, 3 / 2 = 1.5například , doublenebo výpočet průměru množiny celých čísel.
Název rozhraní Definované operátory
IAdditionOperators<TSelf,TOther,TResult> x + y
IBitwiseOperators<TSelf,TOther,TResult> x & y, 'x | y', x ^ ya ~x
IComparisonOperators<TSelf,TOther,TResult> x < y, x > y, x <= ya x >= y
IDecrementOperators<TSelf> --x a x--
IDivisionOperators<TSelf,TOther,TResult> x / y
IEqualityOperators<TSelf,TOther,TResult> x == y a x != y
IIncrementOperators<TSelf> ++x a x++
IModulusOperators<TSelf,TOther,TResult> x % y
IMultiplyOperators<TSelf,TOther,TResult> x * y
IShiftOperators<TSelf,TOther,TResult> x << y a x >> y
ISubtractionOperators<TSelf,TOther,TResult> x - y
IUnaryNegationOperators<TSelf,TResult> -x
IUnaryPlusOperators<TSelf,TResult> +x

Poznámka:

Některá rozhraní definují kontrolovaný operátor kromě běžného nezaškrtnutého operátoru. Zaškrtnuté operátory se volají v kontrolovaných kontextech a umožňují uživatelem definovanému typu definovat chování přetečení. Pokud například implementujete kontrolovaný operátor CheckedSubtraction(TSelf, TOther), musíte také implementovat nezaškrtnutý operátor, Subtraction(TSelf, TOther)například .

Rozhraní funkcí

Rozhraní funkcí definují běžná matematická rozhraní API, která se používají obecněji než u konkrétního číselného rozhraní. Všechna tato rozhraní jsou implementována IFloatingPointIeee754<TSelf>a mohou být implementována jinými relevantními typy v budoucnu.

Název rozhraní Popis
IExponentialFunctions<TSelf> Zveřejňuje exponenciální funkce podporující , , , , , 10^x, a 10^x - 1. 2^x - 12^xe^x - 1e^x
IHyperbolicFunctions<TSelf> Zveřejňuje hyperbolické funkce podporující , , , , , sinh(x), a tanh(x). cosh(x)atanh(x)asinh(x)acosh(x)
ILogarithmicFunctions<TSelf> Zveřejňuje logaritmické funkce podporující ln(x), ln(x + 1), log2(x), log2(x + 1), log10(x)a log10(x + 1).
IPowerFunctions<TSelf> Zveřejňuje funkce napájení podporující x^y.
IRootFunctions<TSelf> Zveřejňuje kořenové funkce podporující cbrt(x) a sqrt(x).
ITrigonometricFunctions<TSelf> Zveřejňuje trigonometrické funkce podporující , , , , , sin(x), a tan(x). cos(x)atan(x)asin(x)acos(x)

Rozhraní pro analýzu a formátování

Analýza a formátování jsou základní koncepty programování. Běžně se používají při převodu uživatelského vstupu na daný typ nebo zobrazení typu uživateli. Tato rozhraní jsou v System oboru názvů.

Název rozhraní Popis
IParsable<TSelf> Zveřejňuje podporu pro T.Parse(string, IFormatProvider) a T.TryParse(string, IFormatProvider, out TSelf).
ISpanParsable<TSelf> Zveřejňuje podporu pro T.Parse(ReadOnlySpan<char>, IFormatProvider) a T.TryParse(ReadOnlySpan<char>, IFormatProvider, out TSelf).
IFormattable1 Zveřejňuje podporu pro value.ToString(string, IFormatProvider).
ISpanFormattable1 Zveřejňuje podporu pro value.TryFormat(Span<char>, out int, ReadOnlySpan<char>, IFormatProvider).

1Toto rozhraní není nové, ani není obecné. Je však implementována všemi typy čísel a představuje inverzní operaci IParsable.

Například následující program přebírá jako vstup dvě čísla a čte je z konzoly pomocí obecné metody, kde je parametr typu omezen na IParsable<TSelf>. Vypočítá průměr pomocí obecné metody, kde jsou parametry typu pro vstupní a výsledné hodnoty omezené na INumber<TSelf>hodnotu a pak zobrazí výsledek v konzole.

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
*/

Viz také