为什么 .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)
期望结果为 3,但得到的却是 2,这可能会产生误导。
According to the documentation, the decimal.Round
method uses a round-to-even algorithm which is not common for most applications. So I always end up writing a custom function to do the more natural round-half-up algorithm:
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;
}
Does anybody know the reason behind this framework design decision?
Is there any built-in implementation of the round-half-up algorithm into the framework? Or maybe some unmanaged Windows API?
It could be misleading for beginners that simply write decimal.Round(2.5m, 0)
expecting 3 as a result but getting 2 instead.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
其他答案解释了为什么银行家算法(又名四舍五入)是一个很好的算法选择都非常正确。 它不像从零舍入一半方法那样受到负面或正面偏差的影响超过最合理的分布。
但问题是为什么 .NET 使用 Banker 的实际舍入作为默认值 - 答案是 Microsoft 遵循了 IEEE 754 标准。 MSDN for Math.Round 下也提到了这一点评论。
另请注意,.NET 通过提供
MidpointRounding
枚举来支持 IEEE 指定的替代方法。 他们当然可以提供更多替代方案来解决关系,但他们选择只是满足IEEE标准。The other answers with reasons why the Banker's algorithm (aka round half to even) is a good choice are quite correct. It does not suffer from negative or positive bias as much as the round half away from zero method over most reasonable distributions.
But the question was why .NET use Banker's actual rounding as default - and the answer is that Microsoft has followed the IEEE 754 standard. This is also mentioned in MSDN for Math.Round under Remarks.
Also note that .NET supports the alternative method specified by IEEE by providing the
MidpointRounding
enumeration. They could of course have provided more alternatives to solving ties, but they choose to just fulfill the IEEE standard.可能是因为这是一个更好的算法。 在执行多次舍入的过程中,您将平均得到所有 0.5 最终均等地向上和向下舍入。 例如,如果您添加一堆四舍五入的数字,这可以更好地估计实际结果。 我想说,尽管这不是某些人所期望的,但这可能是更正确的做法。
Probably because it's a better algorithm. Over the course of many roundings performed, you will average out that all .5's end up rounding equally up and down. This gives better estimations of actual results if you are for instance, adding a bunch of rounded numbers. I would say that even though it isn't what some may expect, it's probably the more correct thing to do.
虽然我无法回答“为什么微软的设计者选择这个作为默认值?”的问题,但我只想指出额外的功能是不必要的。
Math.Round
允许您指定MidpointRounding
:While I cannot answer the question of "Why did Microsoft's designers choose this as the default?", I just want to point out that an extra function is unnecessary.
Math.Round
allows you to specify aMidpointRounding
:小数主要用于金钱; 在处理金钱时,银行家的四舍五入很常见。 或者你可以说。
银行家四舍五入的优点是,平均而言,如果您执行以下操作,您将得到相同的结果:
在相加之前四舍五入可以节省大量成本在计算机出现之前的日子里工作。
(在英国,当我们采用十进制时,银行不会处理半便士,但多年来仍然有半便士硬币,商店经常有以半便士结尾的价格 - 所以有很多四舍五入)
Decimals are mostly used for money; banker’s rounding is common when working with money. Or you could say.
Bankers rounding have the advantage that on average you will get the same result if you:
Rounding before adding up saved a lot of work in the days before computers.
(In the UK when we went decimal banks would not deal with half pence, but for many years there was still a half pence coin and shop often had prices ending in half pence – so lots of rounding)
使用 Round 函数的另一个重载,如下所示:
它将输出 3。 如果您使用,
您将获得银行家的四舍五入。
Use another overload of Round function like this:
It will output 3. And if you use
you will get banker's rounding.