Math.Round a MathF.Round vrátí správně zaokrouhlené výsledky.

Math.Round(Double, Int32) a MathF.Round(Single, Int32)jejich MidpointRounding přetížení nyní vrací hodnotu, která je správně zaokrouhlena na požadovaný počet desetinných číslic na základě přesné hodnoty vstupu. Některé vstupy se teď zaokrouhluje na jiný (a správný) výsledek než v předchozích verzích. Kromě toho digits už argument nemá horní limit.

Verze byla představena

.NET 11 Preview 7

Předchozí chování

Dříve se Math.Round(value, digits, mode) počítaly Round(value * 10^digits, mode) / 10^digits. Vzhledem k tomu, že value * 10^digits obecně není přesně reprezentovatelné, hodnoty mírně pod (nebo nad) desetinnou čárkou by se mohly škálovat na přesnou střední bod nebo přes zaokrouhlenou hranici, což vytvořilo nesprávně zaokrouhlený výsledek. Hodnoty s velkými velikostmi by také mohly během kroku škálování zcela přijít o zlomkové bity.

Argument digits byl také omezen na 0-15 pro double a 0-6 pro float; hodnoty mimo tento rozsah hodil 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

Například 655.925 je uložen jako 655.924999999999954525…, který je pod 655.925 střední bod, takže správný výsledek je 655.92.

Nové chování

Počínaje .NET 11 se výsledek vypočítá z přesné hodnoty vstupu pomocí aritmetické aritmetické hodnoty libovolné přesnosti a vrácená hodnota je nejbližší reprezentovatelná hodnota správně zaokrouhleného desetinného čísla.

Také všechny nezáporné digits hodnoty jsou přijaty; pouze záporné hodnoty vyvolává ArgumentOutOfRangeException. Počet číslic za přesností potřebnou k zaokrouhlení typu (17 pro , 9 prodoublefloat) ponechá hodnotu beze změny, což je správný výsledek.

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)

Typ zásadní změny

Tato změna je změna chování.

Důvod změny

Předchozí výsledky byly nesprávné pro velký zlomek vstupů – přibližně 5% náhodných hodnot v podporovaném digits rozsahu se liší od správně zaokrouhleného výsledku. Předchozí chování také odmítlo nebo nezpracované velké konečné vstupy. Nová implementace je konzistentní se standardem IEEE: zaokrouhlí přesnou hodnotu vstupu a vrátí nejbližší reprezentovatelný výsledek, který odpovídá hodnotě, která value.ToString("F{digits}") už byla vytvořena.

Limit 0-15 a 0-6 digits byl umělým omezením svázaným se starým10^digits přístupem. Vzhledem k tomu, že přesná implementace je správná pro libovolný počet číslic, byl limit zvednut současně, aby se zabránilo druhému behaviorálnímu přerušení později.

Další informace najdete v tématu dotnet/runtime#130574.

Většina kódu nepotřebuje žádnou změnu a výhody z opravených výsledků.

Pokud závisíte na přesném (nesprávném) výstupu, zaokrouhlujte ho explicitně pomocí předchozího přístupu, Math.Round(value * pow10, mode) / pow10například . Případně můžete provést zaokrouhlení, decimal pokud hodnoty představují množství base-10, jako je měna.

double a float jsou binární typy s plovoucí desetinnou čárkou a nemůžou přesně představovat většinu desetinných desetinných míst. Pro přesné zaokrouhlení desetinných míst u desetinných míst raději Decimal. <System.Numerics.Decimal32>, <System.Numerics.Decimal64> a <System.Numerics.Decimal128> jsou typy založené na desítkové soustavě IEEE 754 s rozšířenými rozsahy a funkcemi a jsou také vhodné pro tento typ práce.

Ovlivněná rozhraní API

Stejné opravené chování a zvednutá digits oblast tok přes číselné vstupní body rozhraní, které delegují na tyto metody, double.Roundnapříklad , , float.RoundHalf.Round, a NFloat.Round. Math.Round(Decimal, Int32) a jedno argumenty Math.Round(Double) a MathF.Round(Single) přetížení nejsou ovlivněny.