Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Math.Round(Double, Int32) и , а MathF.Round(Single, Int32)также их MidpointRounding перегрузки теперь возвращают значение, которое правильно округляется до запрошенного количества дробных цифр на основе точного значения входных данных. Некоторые входные данные теперь округляются до другого (и правильного) результата, отличного от предыдущих выпусков. Кроме того, аргумент digits больше не имеет верхнего предела.
Представленная версия
.NET 11 предварительная версия 7
Предыдущее поведение
Math.Round(value, digits, mode) Ранее вычислилиRound(value * 10^digits, mode) / 10^digits. Так как value * 10^digits обычно не является точным представлением, значения немного ниже (или выше) десятичной середины могут масштабироваться в точную середину или через округляющую границу, что привело к неправильно округленному результату. Значения с большими величинами также могут потерять свои дробные биты полностью во время шага масштабирования.
Аргумент digits также был ограничен 0-15 для double и 0-6 для float; значения за пределами этого диапазона.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
Например, 655.925 хранится как 655.924999999999954525…, который находится ниже средней точки, поэтому правильный 655.925 результат имеет значение 655.92.
Новое поведение
Начиная с .NET 11 результат вычисляется из точного значения входных данных с помощью арифметики произвольной точности, а возвращаемое значение — ближайшее представляющее значение для правильно округленного десятичного результата.
Кроме того, принимается любое не отрицательное digits значение; только отрицательные значения вызываются ArgumentOutOfRangeException. Число цифр в точности, необходимой для кругового пути типа (17 для double, 9 для float) оставляет значение неизменным, что является правильным результатом.
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)
Тип разрушающего изменения
Это изменение поведения.
Причина изменения
Предыдущие результаты были неверны для большой доли входных данных — примерно 5% случайных значений в поддерживаемом digits диапазоне отличаются от правильно округленного результата. Предыдущее поведение также отклоняет или неправильно использует большие конечные входные данные. Новая реализация согласована с IEEE: округляет точное значение входных данных и возвращает ближайший представленный результат, который соответствует значению, которое value.ToString("F{digits}") уже создано.
0-15 и 0-6 digits крышки были искусственным ограничением, связанным со старым масштабируемым10^digits подходом. Так как точную реализацию правильно подходит для любого числа цифр, крышка была снята одновременно, чтобы избежать второго перерыва поведения позже.
Дополнительные сведения см. в статье dotnet/runtime#130574.
Рекомендуемое действие
Большинству кода не требуется никаких изменений и преимуществ от исправленных результатов.
Если вы зависите от точных (неправильных) выходных данных, округляется с использованием предыдущего подхода явно, например Math.Round(value * pow10, mode) / pow10. Кроме того, выполните округление, используя, decimal когда значения представляют базовые 10 значений, таких как валюта.
double и float являются двоичными типами с плавающей запятой и не могут точно представлять большинство десятичных дробей. Для точного округления десятичных значений предпочтительна Decimal.
<System.Numerics.Decimal32>, <System.Numerics.Decimal64> и <System.Numerics.Decimal128> являются типами IEEE 754 с расширенными диапазонами и функциональными возможностями, а также подходят для работы этого типа.
Затронутые API
- System.Math.Round(Double, Int32)
- System.Math.Round(Double, Int32, MidpointRounding)
- System.MathF.Round(Single, Int32)
- System.MathF.Round(Single, Int32, MidpointRounding)
То же исправленное поведение и поток диапазона поднимаемого digits диапазона через числовые точки входа интерфейса, которые делегируют эти методы, например double.Round, , float.RoundHalf.Roundи NFloat.Round.
Math.Round(Decimal, Int32) и одно аргументы Math.Round(Double) и MathF.Round(Single) перегрузки не влияют.