舍入到偶数131.575导致奇数而不是偶数
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了舍入到偶数131.575导致奇数而不是偶数相关的知识,希望对你有一定的参考价值。
请考虑以下代码示例:
var tests = new List<double> { 131.505, 131.515, 131.525, 131.535, 131.545, 131.555, 131.565, 131.575, 131.585, 131.595 };
foreach (double n in tests)
{
Console.WriteLine("{0} => {1}", n, Math.Round(n, 2, MidpointRounding.ToEven));
}
131.505 => 131.5
131.515 => 131.51 <- wt*
131.525 => 131.52
131.535 => 131.54
131.545 => 131.54
131.555 => 131.56
131.565 => 131.56
131.575 => 131.57 <- wt*
131.585 => 131.58
131.595 => 131.6
131.515 => 131.52
131.575 => 131.58
为什么MidpointRounding.ToEven
算法产生一个最后有奇数的数字;我有什么办法可以解决这个问题吗?
背景:我将相同的数字传递给php round($n, 2, PHP_ROUND_HALF_EVEN)
函数。目标是让两个脚本产生相同的结果。
我希望能够解释这个特定示例中幕后发生的事情而不是罐头“因为浮点数学被打破”的反应。我想知道为什么PHP能够产生预期的结果,但.NET不是?我想知道.NET的浮点是否被破坏而不是浮点本身。
使用浮点数时会发生多次舍入。
在您显示的代码中,源文本131.515
从十进制数字转换为double
值。由于131.515无法在double
中精确表示,因此会生成最接近的可表示值。这是131.5149999999999863575794734060764312744140625。
因此,当调用Math.round
时,它的值为131.5149999999999863575794734060764312744140625。由于这小于131.515,因此四舍五入为131.51。
正如Mark Dickinson在评论中指出的那样,Math.Round
本身就是一个不完美的实现,并且包含内部舍入错误。对于源文本131.525
,转换为double
产生131.525000000000005684341886080801486968994140625。将此舍入到小数点后的两位小数应该产生131.53。然而,Math.Round
显然通过首先乘以100来计算结果。由于乘以100的数学结果不能完全表示,它将四舍五入到最接近的可表示值,即13152.5。然后将此舍入为整数,使用舍入到最接近的偶数规则生成13152.然后将其除以并将其转换为十进制生成“131.52”。
所以我们不能指望Math.round
产生正确的结果。
以上是关于舍入到偶数131.575导致奇数而不是偶数的主要内容,如果未能解决你的问题,请参考以下文章
2021-11-07:奇偶链表。给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。请尝试使用原地算法完成。你的算法