根据文档,该decimal.Round
方法使用round-to-even算法,这对于大多数应用程序来说并不常见.所以我总是最终编写一个自定义函数来做更自然的圆半算法:
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.
另一个答案是为什么银行家的算法(也就是一半到一半)是一个不错的选择是非常正确的.与大多数合理分布相比,它没有像零方法那样的圆半部分遭受负偏差或正偏差.
但问题是为什么.NET使用Banker的实际舍入作为默认值 - 答案是微软遵循IEEE 754标准.在备注下的MSDN for Math.Round中也提到了这一点.
另请注意,.NET通过提供MidpointRounding
枚举来支持IEEE指定的替代方法.他们当然可以为解决关系提供更多选择,但他们选择只满足IEEE标准.
可能是因为它是一个更好的算法.在执行多次舍入的过程中,您将平均所有.5的最终向上和向下舍入.如果您是例如添加一堆舍入数字,则可以更好地估计实际结果.我会说即使它不是人们所期望的,但这可能是更正确的事情.
虽然我不能回答"为什么微软的设计师选择这个作为默认设置?"的问题,但我只是想指出一个额外的功能是不必要的.
Math.Round
允许您指定MidpointRounding
:
ToEven - 当一个数字介于另外两个数字之间时,它会向最接近的偶数舍入.
AwayFromZero - 当一个数字介于另外两个数字之间时,它会向最接近零的数字四舍五入.
小数几乎用于赚钱 ; 在与钱合作时,银行家的四舍五入很常见.或者你可以说.
大多数银行家都需要十进制类型; 因此,它"银行家的四舍五入"
银行家四舍五入的优势在于,如果您:平均获得相同的结果:
在添加它们之前围绕一组"发票行",
或者将它们加起来然后围绕总数
加起来之前的舍入在计算机之前的日子里节省了大量的工作.
(在英国,当我们去十进制银行不会处理半便士,但多年来仍然有半便士硬币和商店经常价格以半便士结束 - 所以很多四舍五入)