Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of mappen te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen om mappen te wijzigen.
Math.Round(Double, Int32) en , en MathF.Round(Single, Int32)hun MidpointRounding overbelasting, retourneert nu de waarde die correct is afgerond op het aangevraagde aantal fractionele cijfers op basis van de exacte waarde van de invoer. Sommige invoer wordt nu afgerond op een ander (en correct) resultaat dan in eerdere versies. Bovendien heeft het digits argument geen bovengrens meer.
Geïntroduceerde versie
.NET 11 preview 7
Vorig gedrag
Math.Round(value, digits, mode) Eerder berekendRound(value * 10^digits, mode) / 10^digits. Omdat value * 10^digits over het algemeen niet exact vertegenwoordigbaar is, kunnen waarden iets onder (of boven) een decimaal middelpunt worden geschaald naar een exact middelpunt of over een afrondingsgrens, waardoor een onjuist afgerond resultaat ontstaat. Waarden met grote grootten kunnen ook hun fractionele bits volledig verliezen tijdens de schaalstap.
Het digits argument was ook beperkt tot 0-15 voor double en 0-6 voor float; waarden buiten dat bereik.ArgumentOutOfRangeException
Math.Round(655.925, 2, MidpointRounding.AwayFromZero); // 655.93 (incorrect)
Math.Round(1111111111111111.5, 1, MidpointRounding.AwayFromZero); // 1111111111111111.6 (incorrect)
Math.Round(1.5, 16, MidpointRounding.ToEven); // throws ArgumentOutOfRangeException
Wordt bijvoorbeeld 655.925 opgeslagen als 655.924999999999954525…, dat zich onder het 655.925 middelpunt bevindt, dus het juiste resultaat is 655.92.
Nieuw gedrag
Vanaf .NET 11 wordt het resultaat berekend op basis van de exacte waarde van de invoer met behulp van willekeurige rekenkundige precisie en is de geretourneerde waarde de dichtstbijzijnde vertegenwoordigbare waarde voor het correct afgeronde decimale resultaat.
Bovendien wordt elke niet-negatieve digits waarde geaccepteerd; alleen negatieve waarden worden gegenereerd ArgumentOutOfRangeException. Cijfers tellen bij of buiten de precisie die nodig is om het type te afronden (17 voor double, 9 voor float) laten de waarde ongewijzigd, wat het juiste resultaat is.
Math.Round(655.925, 2, MidpointRounding.AwayFromZero); // 655.92 (correct)
Math.Round(1111111111111111.5, 1, MidpointRounding.AwayFromZero); // 1111111111111111.5 (correct)
Math.Round(1.5, 16, MidpointRounding.ToEven); // 1.5 (no longer throws)
Type van brekende verandering
Deze wijziging is een gedragswijziging.
Reden voor wijziging
De vorige resultaten waren onjuist voor een grote fractie van invoer: ongeveer 5% willekeurige waarden in het ondersteunde digits bereik verschillen van het correct afgeronde resultaat. Het vorige gedrag heeft ook grote eindige invoer geweigerd of verkeerd verwerkt. De nieuwe implementatie is IEEE-consistent: hiermee wordt de exacte waarde van de invoer afgerond en wordt het dichtstbijzijnde vertegenwoordigbare resultaat geretourneerd, dat overeenkomt met de waarde die value.ToString("F{digits}") al is geproduceerd.
De 0-15 en 0-6 digits caps waren een kunstmatige beperking die is gekoppeld aan de oude schaal-op-benadering10^digits . Omdat de exacte implementatie juist is voor elk aantal cijfers, werd de limiet tegelijkertijd opgeheven om later een tweede gedragsonderbreking te voorkomen.
Zie dotnet/runtime#130574 voor meer informatie.
Aanbevolen actie
De meeste code heeft geen verandering nodig en profiteert van de gecorrigeerde resultaten.
Als u afhankelijk bent van de exacte eerdere (onjuiste) uitvoer, rondt u de vorige benadering bijvoorbeeld expliciet Math.Round(value * pow10, mode) / pow10af. U kunt de afronding ook uitvoeren wanneer decimal de waarden basis-10 hoeveelheden vertegenwoordigen, zoals valuta.
double en float zijn binaire typen drijvende komma en kunnen niet exact de meeste decimale breuken vertegenwoordigen. Geef de voorkeur Decimalaan voor exact decimaal afronden van decimale hoeveelheden.
<System.Numerics.Decimal32>, <System.Numerics.Decimal64> en <System.Numerics.Decimal128> zijn IEEE 754 decimale typen met uitgebreide bereiken en functionaliteit en zijn ook geschikt voor dit type werk.
Betreffende API's
- System.Math.Round(Double, Int32)
- System.Math.Round(Double, Int32, MidpointRounding)
- System.MathF.Round(Single, Int32)
- System.MathF.Round(Single, Int32, MidpointRounding)
Hetzelfde gecorrigeerde gedrag en opgeheven digits bereikstroom door de numerieke interfaceinvoerpunten die aan deze methoden delegeren, bijvoorbeeld double.Round, float.Round, , Half.Rounden NFloat.Round.
Math.Round(Decimal, Int32) en het enkelvoudige argument Math.Round(Double) en MathF.Round(Single) de overbelasting worden niet beïnvloed.