为什么.NET使用银行家舍入作为默认?

根据文档, decimal.Round方法使用了一个循环算法,这在大多数应用程序中并不常见。 所以我总是最终编写一个自定义函数来做更自然的round-half-up算法:

 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)可能会decimal.Round(2.5m, 0)产生误解,因此期待3结果,而不是2。

可能是因为它是一个更好的算法。 在执行多次调整的过程中,您将平均得出所有.5的结果都是同样的上下移动。 这样可以更好地估计实际结果,例如,您可以添加一些舍入的数字。 我会说,即使这不是某些人可能期望的,也许是更正确的做法。

另一个答案是为什么银行家的算法(又名半到平 )是一个很好的选择是非常正确的。 在大多数合理的分布情况下,它不会受到远离零方法的半个偏差或正偏差的影响。

但问题是,为什么.NET使用银行家的实际舍入作为默认值 – 答案是微软遵循IEEE 754标准。 在备注中的Math.Round的MSDN中也提到了这一点。

另外请注意,.NET通过提供MidpointRounding枚举来支持IEEE指定的替代方法。 他们当然可以提供更多的解决方案,但他们选择符合IEEE标准。

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

Math.Round允许你指定一个MidpointRounding

  • ToEven – 当一个数字位于另外两个数字的中间时,向最接近的偶数进行四舍五入。
  • AwayFromZero – 当一个数字位于另外两个数字的中间时,向最接近的数字四舍五入。

小数主要用于金钱 ; 银行业务的四舍五入是常见的工作与金钱 。 或者你可以说。

大多数银行家需要小数类型; 因此它是“银行家四舍五入”

银行家四舍五入有以下优势:平均而言,如果您符合以下条件,您将获得相同的结果:

  • 在添加它们之前,先围绕一组“发票行”
  • 或者把它们加起来,然后总计

加起来之前的舍入在电脑前的日子里保存了很多工作。

(在英国,当我们去了十进制银行不会处理半便士,但多年来仍然有一个半便士硬币和商店往往价格以半便士结束 – 所以四舍五入很多)

使用Round函数的另一个重载如下:

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

它会输出3 。 如果你使用

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

你会得到银行家的四舍五入。