为什么.NET默认使用banker's舍入?

根据文档,decimal.Round方法使用一种四舍五入到偶数的算法,这在大多数应用程序中并不常见。所以我总是写一个自定义函数来实现更自然的四舍五入算法:

public static decimal RoundHalfUp(this decimal d, int decimals)
{
if (decimals < 0)
{
throw new ArgumentException("The decimals must be non-negative",
"decimals");
}


decimal multiplier = (decimal)Math.Pow(10, decimals);
decimal number = d * multiplier;


if (decimal.Truncate(number) < number)
{
number += 0.5m;
}
return decimal.Round(number) / multiplier;
}

有人知道这个框架设计决策背后的原因吗?

框架中是否有舍入半取半算法的内置实现?或者是一些非托管的Windows API?

对于初学者来说,简单地编写decimal.Round(2.5m, 0),期望结果是3,但结果却是2,这可能会产生误导。

68440 次浏览

可能因为这是一个更好的算法。在多次四舍五入的过程中,您将平均出所有的。5最终都是上下相等的四舍五入。这可以更好地估计实际结果,例如,添加一堆四舍五入的数字。我想说,尽管这不是一些人所期望的,但这可能是更正确的做法。

虽然我不能回答“为什么微软的设计师选择这个作为默认?”的问题,但我只想指出,额外的功能是不必要的。

Math.Round允许你指定一个MidpointRounding:

  • 至偶数——当一个数字位于另外两个数字的中间时,将它四舍五入到最接近的偶数。
  • awayfrom0 -当一个数字位于另外两个数字的中间时,它会四舍五入到距离0最近的数字。

小数主要用于;银行家舍入在使用时很常见。或者你可以说。

需要资金的主要是银行家 十进制类型;因此确实如此 “银行家的舍入”< / p >

银行家舍入的优势是,平均而言,如果你:

  • 把一组“发票行”四舍五入,然后再加起来,
  • 或者把它们加起来,然后四舍五入

在没有计算机的时代,先四舍五入再加可以节省很多工作。

(在英国,十进位银行不处理半便士,但多年来仍然有半便士硬币,商店的价格经常以半便士结尾,所以有很多四舍五入)

其他回答的原因,银行家的算法(又名半圆到偶数)是一个很好的选择是相当正确的。在大多数合理的分布上,它不会像距离0的一半圆方法那样受到负或正偏差的影响。

但问题是。net为什么使用Banker的实际舍入作为默认值——答案是微软遵循了IEEE 754标准。这也在数学MSDN。轮的备注中提到过。

还要注意,. net通过提供MidpointRounding枚举来支持IEEE指定的替代方法。他们当然可以提供更多的选择来解决关系,但他们选择只满足IEEE标准。

使用另一个重载Round函数,如下所示:

decimal.Round(2.5m, 0,MidpointRounding.AwayFromZero)

它将输出3.。如果你用

decimal.Round(2.5m, 0,MidpointRounding.ToEven)

你会得到银行四舍五入。