C#银行家的舍入错误

double a = 18.565 return Math.Round(a,2) 

..返回18.57。
对于其他所有数字,我尝试过银行家的舍入按预期工作,例如Math.Round(2.565,2)返回2.56。

任何线索为什么以及何时发生? 这是错误还是我错过了关于银行家四舍五入的事情?

谢谢..

正如马修所说,18.565无法准确表达。 使用的实际值是18.565000000000001278976924368180334568023681640625(使用DoubleConverter找到),这显然超出了一半。 现在我有一种偷偷摸摸的感觉, 有时 Math.Round会考虑一个实际上超出中间点的值,但是它可以准确地表示为接近中间点,正好那个点上。 但是,我没有看到任何描述应用情况的文档,显然在这种情况下并没有发生。 我不想依赖它。

当然,即使是舍入值也不是18.57。 它实际上是18.57000000000000028421709430404007434844970703125。

从根本上说,如果你真的非常关心准确表示小数值,你应该使用decimal 。 这不只是在Math.Round – 它涉及处理浮点值的每个方面。

确实Math.Round提供了正确的价值,当然:

 decimal m = 18.565m; Console.WriteLine(Math.Round(m, 2)); // Prints 18.56 

18.565不能完全表示为double。 因此,二进制表示略高,因此它向上舍入。 如果使用小数:

 decimal a = 18.565m; return Math.Round(a,2) 

它可以准确表示,你不会有这个问题。

我的猜测是FP表示意味着它实际上不是尾随5; FP的危险!

但这很好用,但是:

  decimal a = 18.565M; // <===== decimal var s = Math.Round(a, 2); 

Double是一个浮点值,所以如果你把它写成18.565,它实际上在内存中就像18.565000000000000000000000000000000001,因此它超过了中点。