Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Math.Round(Double, Int32) et , et MathF.Round(Single, Int32)leurs MidpointRounding surcharges, retournent maintenant la valeur correctement arrondie au nombre demandé de chiffres fractionnaires en fonction de la valeur exacte de l’entrée. Certaines entrées sont désormais arrondies à un résultat différent (et correct) par rapport aux versions précédentes. En outre, l’argument digits n’a plus de limite supérieure.
Version introduite
.NET 11 Preview 7
Comportement antérieur
Auparavant, Math.Round(value, digits, mode) calculé Round(value * 10^digits, mode) / 10^digits. Étant donné qu’en value * 10^digits règle générale, les valeurs légèrement inférieures (ou supérieures) d’un milieu décimal peuvent être mises à l’échelle dans un milieu exact ou sur une limite arrondie, ce qui a produit un résultat arrondi incorrect. Les valeurs avec de grandes grandeurs peuvent également perdre entièrement leurs bits fractionnels pendant l’étape de mise à l’échelle.
L’argument digits était également limité à 0-15 pour double et 0-6 pour float; les valeurs en dehors de cette plage ont levé 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
Par exemple, 655.925 est stocké en tant que 655.924999999999954525…, qui est en dessous du 655.925 point de milieu, donc le résultat correct est 655.92.
Nouveau comportement
À partir de .NET 11, le résultat est calculé à partir de la valeur exacte de l’entrée à l’aide d’une arithmétique de précision arbitraire et la valeur retournée est la valeur la plus proche pouvant être représentée par le résultat décimal arrondi correctement.
En outre, toute valeur non négative digits est acceptée ; seules les valeurs négatives lèvent ArgumentOutOfRangeException. Le nombre de chiffres au-delà de la précision nécessaire pour aller-retour sur le type (17 pour double, 9 pour float) laisse la valeur inchangée, qui est le résultat correct.
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 de changement cassant
Ce changement est un changement de comportement.
Raison du changement
Les résultats précédents étaient incorrects pour une grande fraction d’entrées : environ 5% de valeurs aléatoires sur la plage prise en charge digits diffèrent du résultat arrondi correctement. Le comportement précédent a également rejeté ou mal géré des entrées finies volumineuses. La nouvelle implémentation est cohérente ieee : elle arrondit la valeur exacte de l’entrée et retourne le résultat représenté le plus proche, qui correspond à la valeur déjà value.ToString("F{digits}") produite.
Les capuchons 0-15 et 0-6 digits étaient une limitation artificielle liée à l’ancienne échelle par10^digits approche. Étant donné que l’implémentation exacte est correcte pour n’importe quel nombre de chiffres, la limite a été levée en même temps pour éviter une deuxième rupture comportementale plus tard.
Pour plus d’informations, consultez dotnet/runtime#130574.
Action recommandée
La plupart du code n’a besoin d’aucune modification et bénéficie des résultats corrigés.
Si vous dépendez de la sortie exacte (incorrecte), arrondissez à l’aide de l’approche précédente explicitement, par exemple Math.Round(value * pow10, mode) / pow10. Vous pouvez également effectuer l’arrondi à l’aide decimal lorsque les valeurs représentent des quantités de base-10 telles que la devise.
double et float sont des types à virgule flottante binaire et ne peuvent pas représenter exactement la plupart des fractions décimales. Pour l’arrondi décimal exact des quantités décimales, préférez Decimal.
<System.Numerics.Decimal32>, <System.Numerics.Decimal64> et <System.Numerics.Decimal128> sont des types IEEE 754 décimaux avec des plages et des fonctionnalités développées, et sont également adaptés à ce type de travail.
API affectées
- System.Math.Round(Double, Int32)
- System.Math.Round(Double, Int32, MidpointRounding)
- System.MathF.Round(Single, Int32)
- System.MathF.Round(Single, Int32, MidpointRounding)
Le même comportement corrigé et la plage levée transitent digits par les points d’entrée d’interface numérique qui délèguent à ces méthodes, par exemple, double.Round, , float.RoundHalf.Round, et NFloat.Round.
Math.Round(Decimal, Int32) et les surcharges Math.Round(Double) et MathF.Round(Single) arguments uniques ne sont pas affectés.