Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Math.Round(Double, Int32) e MathF.Round(Single, Int32), e suas MidpointRounding sobrecargas, agora retornam o valor arredondado corretamente para o número solicitado de dígitos fracionários com base no valor exato da entrada. Algumas entradas agora são arredondadas para um resultado diferente (e correto) do que nas versões anteriores. Além disso, o digits argumento não tem mais um limite superior.
Versão introduzida
.NET 11 Versão Prévia 7
Comportamento anterior
Anteriormente, Math.Round(value, digits, mode) computado Round(value * 10^digits, mode) / 10^digits. Como value * 10^digits geralmente não é exatamente representável, valores ligeiramente abaixo (ou acima) de um ponto médio decimais podem ser dimensionados em um ponto médio exato ou em um limite de arredondamento, o que produziu um resultado arredondado incorretamente. Valores com grandes magnitudes também podem perder seus bits fracionários inteiramente durante a etapa de dimensionamento.
O digits argumento também foi limitado a 0-15 para double e 0-6 para float; valores fora desse intervalo jogados 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
Por exemplo, 655.925 é armazenado como 655.924999999999954525…, que está abaixo do 655.925 ponto médio, portanto, o resultado correto é 655.92.
Novo comportamento
A partir do .NET 11, o resultado é calculado do valor exato da entrada usando aritmética de precisão arbitrária e o valor retornado é o valor representável mais próximo do resultado decimal arredondado corretamente.
Além disso, qualquer valor não negativo digits é aceito; somente valores negativos são gerados ArgumentOutOfRangeException. Contagens de dígitos em ou além da precisão necessária para viagem de ida e volta do tipo (17 para double, 9 para float) deixam o valor inalterado, que é o resultado correto.
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)
Tipo de mudança disruptiva
Esta é uma alteração comportamental.
Motivo da alteração
Os resultados anteriores estavam incorretos para uma grande fração de entradas— cerca de 5% de valores aleatórios no intervalo com digits suporte diferem do resultado arredondado corretamente. O comportamento anterior também rejeitou ou lidou mal com entradas finitas grandes. A nova implementação é consistente com IEEE: arredonda o valor exato da entrada e retorna o resultado representável mais próximo, que corresponde ao valor já value.ToString("F{digits}") produzido.
As tampas 0-15 e 0-6 digits eram uma limitação artificial ligada à velha abordagem scale-by-10^digits . Como a implementação exata está correta para qualquer contagem de dígitos, a tampa foi levantada ao mesmo tempo para evitar uma segunda interrupção comportamental mais tarde.
Para obter mais informações, consulte dotnet/runtime#130574.
Ação recomendada
A maioria dos códigos não precisa de nenhuma alteração e benefícios dos resultados corrigidos.
Se você depender da saída exata anterior (incorreta), arredondar usando a abordagem anterior explicitamente, por exemplo, Math.Round(value * pow10, mode) / pow10. Como alternativa, execute o arredondamento usando decimal quando os valores representam quantidades base-10, como moeda.
double e float são tipos binários de ponto flutuante e não podem representar exatamente a maioria das frações decimais. Para arredondamento decimais exato de quantidades decimais, prefira Decimal.
<System.Numerics.Decimal32>, <System.Numerics.Decimal64> e <System.Numerics.Decimal128> são tipos baseados emcimal IEEE 754 com intervalos e funcionalidades expandidos e também são adequados para esse tipo de trabalho.
APIs afetadas
- System.Math.Round(Double, Int32)
- System.Math.Round(Double, Int32, MidpointRounding)
- System.MathF.Round(Single, Int32)
- System.MathF.Round(Single, Int32, MidpointRounding)
O mesmo comportamento corrigido e o fluxo de intervalo levantado digits por meio dos pontos de entrada da interface numérica que delegam a esses métodos, por exemplo, double.Round, float.Rounde Half.RoundNFloat.Round.
Math.Round(Decimal, Int32) e o argumento Math.Round(Double) único e MathF.Round(Single) as sobrecargas não são afetados.