为什么.NET使用银行家的舍入作为默认值?
根据文档, 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)
产生误解,因为它只是简单地写入decimal.Round(2.5m, 0)
期望结果为3,但取而代之。
可能是因为它是一个更好的算法。 在执行多次调整的过程中,您将平均得出所有.5最终都会同时上下调整。 这可以更好地估计实际结果,例如,如果您添加一组舍入的数字。 我会说,即使这不是某些人所期望的,但这可能是更正确的做法。
另一个答案是为什么银行家算法(又名半到平)是一个很好的选择是非常正确的。 在大多数合理的分布情况下,它不会受到远离零方法的一半的负面或正面偏差。
但问题是为什么.NET使用Banker的实际舍入作为默认值 - 答案是微软遵循了IEEE 754标准。 在备注中的Math.Round的MSDN中也提到了这一点。
还要注意,.NET通过提供MidpointRounding
枚举来支持IEEE指定的替代方法。 他们当然可以为解决关系提供更多的选择,但他们选择符合IEEE标准。
虽然我无法回答“为什么微软的设计师选择这个作为默认设置?”,我只想指出一个额外的功能是不必要的。
Math.Round
允许你指定一个MidpointRounding
: