Delen via


Algemene wiskunde

.NET 7 introduceert nieuwe wiskundige algemene interfaces voor de basisklassebibliotheek. De beschikbaarheid van deze interfaces betekent dat u een typeparameter van een algemeen type of methode kunt beperken als 'getalachtig'. Daarnaast kunt u met C# 11 en hoger interfaceleden definiërenstatic virtual. Omdat operators moeten worden gedeclareerd als static, kunnen met deze nieuwe C#-functie operators worden gedeclareerd in de nieuwe interfaces voor numerieke typen.

Met deze innovaties kunt u algemene wiskundige bewerkingen uitvoeren, dat wil zeggen, zonder dat u het exacte type hoeft te kennen waarmee u werkt. Als u bijvoorbeeld een methode wilt schrijven waarmee twee getallen worden opgetellen, moest u eerder een overbelasting van de methode voor elk type toevoegen (bijvoorbeeld static int Add(int first, int second) en static float Add(float first, float second)). U kunt nu één algemene methode schrijven, waarbij de typeparameter is beperkt tot een getalachtig type. Voorbeeld:

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

In deze methode is de typeparameter T beperkt tot een type dat de nieuwe INumber<TSelf> interface implementeert. INumber<TSelf> implementeert de IAdditionOperators<TSelf,TOther,TResult> interface, die de +-operator bevat. Hierdoor kan de methode de twee getallen algemeen optellen. De methode kan worden gebruikt met elk van . De ingebouwde numerieke typen van NET, omdat ze allemaal zijn bijgewerkt voor implementatie INumber<TSelf> in .NET 7.

Bibliotheekauteurs profiteren het meeste van de algemene wiskundige interfaces, omdat ze hun codebasis kunnen vereenvoudigen door 'redundante' overbelastingen te verwijderen. Andere ontwikkelaars profiteren indirect, omdat de API's die ze gebruiken, meer typen kunnen ondersteunen.

De interfaces

De interfaces zijn ontworpen om beide fijnmazig genoeg te zijn, zodat gebruikers hun eigen interfaces kunnen definiëren, terwijl ze ook granulair genoeg zijn dat ze gemakkelijk te gebruiken zijn. In die mate zijn er enkele kernen van numerieke interfaces waarmee de meeste gebruikers communiceren, zoals INumber<TSelf> en IBinaryInteger<TSelf>. De meer verfijnde interfaces, zoals IAdditionOperators<TSelf,TOther,TResult> en ITrigonometricFunctions<TSelf>, ondersteunen deze typen en zijn beschikbaar voor ontwikkelaars die hun eigen domeinspecifieke numerieke interfaces definiëren.

Numerieke interfaces

In deze sectie worden de interfaces beschreven System.Numerics waarin aantal-achtige typen en de beschikbare functionaliteit worden beschreven.

Interfacenaam Beschrijving
IBinaryFloatingPointIeee754<TSelf> Maakt API's algemeen beschikbaar voor binaire typen drijvende komma1 die de IEEE 754-standaard implementeren.
IBinaryInteger<TSelf> Maakt API's algemeen beschikbaar voor binaire gehele getallen2.
IBinaryNumber<TSelf> Maakt API's algemeen beschikbaar voor binaire getallen.
IFloatingPoint<TSelf> Maakt API's algemeen beschikbaar voor typen drijvende komma' s.
IFloatingPointIeee754<TSelf> Stelt API's beschikbaar die gangbaar zijn voor typen drijvende komma die de IEEE 754-standaard implementeren.
INumber<TSelf> Stelt API's beschikbaar die vergelijkbaar zijn met vergelijkbare getaltypen (in feite het 'reële' numerieke domein).
INumberBase<TSelf> Maakt API's algemeen beschikbaar voor alle getaltypen (in feite het 'complexe' numerieke domein).
ISignedNumber<TSelf> Stelt API's beschikbaar die gebruikelijk zijn voor alle ondertekende getaltypen (zoals het concept ).NegativeOne
IUnsignedNumber<TSelf> Maakt API's algemeen beschikbaar voor alle niet-ondertekende getaltypen.
IAdditiveIdentity<TSelf,TResult> Maakt het concept van (x + T.AdditiveIdentity) == x.
IMinMaxValue<TSelf> Maakt het concept van T.MinValue en T.MaxValue.
IMultiplicativeIdentity<TSelf,TResult> Maakt het concept van (x * T.MultiplicativeIdentity) == x.

1De binaire typen drijvende komma zijn Double (double), Halfen Single (float).

2De binaire gehele getallen zijn Byte (), Int16 (byte), Int32 (short), (int), Int64 (), (long), Int128IntPtr (nint), (), SByte (sbyte), (), UInt16 (ushort), UInt32 (uintulong), UInt128UInt64 en UIntPtr ().nuint

De interface die u waarschijnlijk rechtstreeks gebruikt, is INumber<TSelf>, wat ongeveer overeenkomt met een reëel getal. Als een type deze interface implementeert, betekent dit dat een waarde een teken heeft (dit omvat unsigned typen, die als positief worden beschouwd) en kan worden vergeleken met andere waarden van hetzelfde type. INumberBase<TSelf> geeft meer geavanceerde concepten, zoals complexe en imaginaire getallen, bijvoorbeeld de vierkantswortel van een negatief getal. Andere interfaces, zoals IFloatingPointIeee754<TSelf>, zijn gemaakt omdat niet alle bewerkingen zinvol zijn voor alle getaltypen, bijvoorbeeld het berekenen van de vloer van een getal, is alleen zinvol voor typen drijvende komma. In de .NET-basisklassebibliotheek wordt het type Double drijvende komma geïmplementeerd IFloatingPointIeee754<TSelf> , maar Int32 niet.

Verschillende interfaces worden ook geïmplementeerd door verschillende andere typen, waaronder Char, , DateOnly, DateTimeOffsetDateTime, Decimal, , Guid, , en TimeOnlyTimeSpan.

In de volgende tabel ziet u enkele van de kern-API's die door elke interface worden weergegeven.

Interface API-naam Beschrijving
IBinaryInteger<TSelf> DivRem Berekent het quotiënt en de rest tegelijk.
LeadingZeroCount Telt het aantal voorloopnul bits in de binaire weergave.
PopCount Telt het aantal ingestelde bits in de binaire weergave.
RotateLeft Hiermee draait u bits naar links, ook wel een cirkelvormige linkerdienst genoemd.
RotateRight Hiermee draait u bits naar rechts, ook wel een cirkelvormige rechter shift genoemd.
TrailingZeroCount Telt het aantal volgnullen bits in de binaire weergave.
IFloatingPoint<TSelf> Ceiling Rondt de waarde af naar positief oneindigheid. +4,5 wordt +5 en -4,5 wordt -4.
Floor Rondt de waarde af op negatieve oneindigheid. +4,5 wordt +4 en -4,5 wordt -5.
Round Rondt de waarde af met behulp van de opgegeven afrondingsmodus.
Truncate Rondt de waarde af naar nul. +4,5 wordt +4 en -4,5 wordt -4.
IFloatingPointIeee754<TSelf> E Hiermee wordt een waarde opgehaald die het getal van Euler vertegenwoordigt voor het type.
Epsilon Hiermee haalt u de kleinste vertegenwoordigbare waarde op die groter is dan nul voor het type.
NaN Hiermee haalt u een waarde NaN op voor het type.
NegativeInfinity Hiermee haalt u een waarde -Infinity op voor het type.
NegativeZero Hiermee haalt u een waarde -Zero op voor het type.
Pi Hiermee haalt u een waarde Pi op voor het type.
PositiveInfinity Hiermee haalt u een waarde +Infinity op voor het type.
Tau Hiermee haalt u een waarde op die (2 * Pi) voor het type vertegenwoordigt Tau .
(Overig) (Implementeert de volledige set interfaces die worden vermeld onder Functie-interfaces.)
INumber<TSelf> Clamp Hiermee beperkt u een waarde tot niet meer en niet minder dan de opgegeven minimum- en maximumwaarde.
CopySign Hiermee stelt u het teken van een opgegeven waarde in op hetzelfde als een andere opgegeven waarde.
Max Retourneert de grotere van twee waarden, die worden geretourneerd NaN als een van beide invoer is NaN.
MaxNumber Retourneert de grotere van twee waarden, die het getal retourneren als één invoer is NaN.
Min Retourneert de mindere van twee waarden, die worden geretourneerd NaN als een van beide invoer is NaN.
MinNumber Retourneert de mindere van twee waarden, die het getal retourneren als één invoer is NaN.
Sign Retourneert -1 voor negatieve waarden, 0 voor nul en +1 voor positieve waarden.
INumberBase<TSelf> One Hiermee haalt u de waarde 1 voor het type op.
Radix Hiermee haalt u de radix of basis voor het type op. Int32 retourneert 2. Decimal retourneert 10.
Zero Hiermee haalt u de waarde 0 voor het type op.
CreateChecked Hiermee maakt u een waarde en genereert u een OverflowException als de invoer niet past.1
CreateSaturating Hiermee maakt u een waarde, klem aan T.MinValue of T.MaxValue als de invoer niet past.1
CreateTruncating Hiermee maakt u een waarde op basis van een andere waarde, die rondloopt als de invoer niet past.1
IsComplexNumber Retourneert waar als de waarde een niet-nul reëel deel en een niet-nul imaginair deel heeft.
IsEvenInteger Retourneert waar als de waarde een even geheel getal is. 2.0 retourneert trueen 2,2 retourneert false.
IsFinite Retourneert waar als de waarde niet oneindig is en niet NaN.
IsImaginaryNumber Retourneert waar als de waarde een echt deel van nul heeft. Dit betekent 0 imaginair en 1 + 1i niet.
IsInfinity Retourneert waar als de waarde oneindigheid vertegenwoordigt.
IsInteger Retourneert waar als de waarde een geheel getal is. 2.0 en 3.0 retourneren true, en 2.2 en 3.1 retourneren false.
IsNaN Retourneert waar als de waarde vertegenwoordigt NaN.
IsNegative Retourneert waar als de waarde negatief is. Dit omvat -0.0.
IsPositive Retourneert waar als de waarde positief is. Dit omvat 0 en +0,0.
IsRealNumber Retourneert waar als de waarde een imaginair deel van nul heeft. Dit betekent dat 0 echt is zoals alle INumber<T> typen.
IsZero Retourneert waar als de waarde nul vertegenwoordigt. Dit omvat 0, +0.0 en -0.0.
MaxMagnitude Retourneert de waarde met een hogere absolute waarde, die retourneert NaN als een van beide invoer is NaN.
MaxMagnitudeNumber Retourneert de waarde met een hogere absolute waarde, waarbij het getal als één invoer wordt NaNgeretourneerd.
MinMagnitude Retourneert de waarde met een minder absolute waarde, die retourneert NaN als een van beide invoer is NaN.
MinMagnitudeNumber Retourneert de waarde met een minder absolute waarde, waarbij het getal als één invoer wordt NaNgeretourneerd.
ISignedNumber<TSelf> NegativeOne Hiermee haalt u de waarde -1 voor het type op.

1Bekijk de volgende voorbeelden om inzicht te verkrijgen in het gedrag van de drie Create* methoden.

Voorbeeld wanneer u een waarde krijgt die te groot is:

  • byte.CreateChecked(384) zal een OverflowException.
  • byte.CreateSaturating(384) retourneert 255 omdat 384 groter is dan Byte.MaxValue (dat is 255).
  • byte.CreateTruncating(384) retourneert 128 omdat het de laagste 8 bits (384 heeft een hexweergave van 0x0180en de laagste 8 bits is 0x80, wat 128 is).

Voorbeeld wanneer u een waarde krijgt die te klein is:

  • byte.CreateChecked(-384) zal een OverflowException.
  • byte.CreateSaturating(-384) retourneert 0 omdat -384 kleiner is dan Byte.MinValue (dat is 0).
  • byte.CreateTruncating(-384) retourneert 128 omdat het de laagste 8 bits (384 heeft een hexweergave van 0xFE80en de laagste 8 bits is 0x80, wat 128 is).

De Create* methoden hebben ook enkele speciale overwegingen voor IEEE 754-drijvendekommatypen, zoals float en double, omdat ze de speciale waarden PositiveInfinityhebben , NegativeInfinityen NaN. Alle drie Create* de API's gedragen zich als CreateSaturating. Ook, terwijl MinValue en MaxValue het grootste negatieve/positieve "normale" getal, de werkelijke minimum- en maximumwaarden zijn NegativeInfinity en PositiveInfinity, dus ze klemen op deze waarden in plaats daarvan.

Operatorinterfaces

De operatorinterfaces komen overeen met de verschillende operators die beschikbaar zijn voor de C#-taal.

  • Ze koppelen expliciet geen bewerkingen, zoals vermenigvuldigen en delen, omdat dat niet juist is voor alle typen. Is bijvoorbeeld Matrix4x4 * Matrix4x4 geldig, maar Matrix4x4 / Matrix4x4 is niet geldig.
  • Ze staan doorgaans toe dat de invoer- en resultaattypen verschillen om scenario's te ondersteunen, zoals het delen van twee gehele getallen, om een double, bijvoorbeeld 3 / 2 = 1.5, of het gemiddelde van een set gehele getallen te berekenen.
Interfacenaam Gedefinieerde operators
IAdditionOperators<TSelf,TOther,TResult> x + y
IBitwiseOperators<TSelf,TOther,TResult> x & y, 'x | y', x ^ yen ~x
IComparisonOperators<TSelf,TOther,TResult> x < y, x > y, x <= y en x >= y
IDecrementOperators<TSelf> --x en x--
IDivisionOperators<TSelf,TOther,TResult> x / y
IEqualityOperators<TSelf,TOther,TResult> x == y en x != y
IIncrementOperators<TSelf> ++x en x++
IModulusOperators<TSelf,TOther,TResult> x % y
IMultiplyOperators<TSelf,TOther,TResult> x * y
IShiftOperators<TSelf,TOther,TResult> x << y en x >> y
ISubtractionOperators<TSelf,TOther,TResult> x - y
IUnaryNegationOperators<TSelf,TResult> -x
IUnaryPlusOperators<TSelf,TResult> +x

Notitie

Sommige interfaces definiëren een ingeschakelde operator naast een normale niet-gecontroleerde operator. Gecontroleerde operators worden aangeroepen in gecontroleerde contexten en stellen een door de gebruiker gedefinieerd type in staat om overloopgedrag te definiëren. Als u bijvoorbeeld een gecontroleerde operator implementeert, CheckedSubtraction(TSelf, TOther)moet u ook de uitgeschakelde operator implementeren, bijvoorbeeld Subtraction(TSelf, TOther).

Functie-interfaces

De functieinterfaces definiëren algemene wiskundige API's die breder van toepassing zijn dan op een specifieke numerieke interface. Deze interfaces worden allemaal geïmplementeerd door IFloatingPointIeee754<TSelf>en kunnen in de toekomst worden geïmplementeerd door andere relevante typen.

Interfacenaam Beschrijving
IExponentialFunctions<TSelf> Stelt exponentiële functies beschikbaar die ondersteuning biedene^x, e^x - 1, 2^x, , 2^x - 1en 10^x.10^x - 1
IHyperbolicFunctions<TSelf> Maakt hyperbolische functies beschikbaar die ondersteunenacosh(x), , atanh(x)asinh(x), , cosh(x), sinh(x)en tanh(x).
ILogarithmicFunctions<TSelf> Biedt logaritmische functies die ondersteuning bieden ln(x)voor, ln(x + 1), log2(x), log2(x + 1), en log10(x)log10(x + 1).
IPowerFunctions<TSelf> Maakt energiefuncties beschikbaar die ondersteuning bieden x^y.
IRootFunctions<TSelf> Maakt hoofdfuncties beschikbaar die ondersteunen cbrt(x) en sqrt(x).
ITrigonometricFunctions<TSelf> Maakt trigonometrische functies beschikbaar die ondersteuning bieden acos(x)voor, asin(x), atan(x), cos(x), en sin(x)tan(x).

Interfaces voor parseren en opmaken

Parseren en opmaken zijn kernconcepten in programmeren. Ze worden vaak gebruikt bij het converteren van gebruikersinvoer naar een bepaald type of het weergeven van een type naar de gebruiker. Deze interfaces bevinden zich in de System naamruimte.

Interfacenaam Beschrijving
IParsable<TSelf> Biedt ondersteuning voor T.Parse(string, IFormatProvider) en T.TryParse(string, IFormatProvider, out TSelf).
ISpanParsable<TSelf> Biedt ondersteuning voor T.Parse(ReadOnlySpan<char>, IFormatProvider) en T.TryParse(ReadOnlySpan<char>, IFormatProvider, out TSelf).
IFormattable1 Biedt ondersteuning voor value.ToString(string, IFormatProvider).
ISpanFormattable1 Biedt ondersteuning voor value.TryFormat(Span<char>, out int, ReadOnlySpan<char>, IFormatProvider).

1Deze interface is niet nieuw en is ook niet algemeen. Het wordt echter geïmplementeerd door alle getaltypen en vertegenwoordigt de inverse werking van IParsable.

Het volgende programma gebruikt bijvoorbeeld twee getallen als invoer, waarbij deze worden gelezen vanuit de console met behulp van een algemene methode waarbij de typeparameter wordt beperkt IParsable<TSelf>. Het berekent het gemiddelde met behulp van een algemene methode waarbij de typeparameters voor de invoer- en resultaatwaarden beperkt zijn en INumber<TSelf>het resultaat vervolgens weergeeft aan de console.

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

Zie ook