舍入到偶数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));
}

And its output

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

I was expecting

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导致奇数而不是偶数的主要内容,如果未能解决你的问题,请参考以下文章

四舍六入五凑偶

输入一个整数判断是奇数还是偶数,C语言程序

C++将整数数组分割成奇数和偶数两个数组的源码

2021-11-07:奇偶链表。给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。请尝试使用原地算法完成。你的算法

判断奇数偶数的C++语言程序

偶数,奇数前n项和