根据文档,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 的初学者来说,这可能会产生误导。
其他解释为什么银行家算法(又名 round half to even)是一个不错的选择的原因是非常正确的。在最合理的分布上,它不会像 round half away from zero 方法那样遭受负或正偏差。
但问题是 .NET 为什么默认使用 Banker 的实际舍入 - 答案是 Microsoft 遵循了 IEEE 754 标准。这在备注下的 MSDN for Math.Round 中也有提及。
另请注意,.NET 通过提供 MidpointRounding
枚举来支持 IEEE 指定的替代方法。他们当然可以提供 more alternatives 来解决关系,但他们选择只满足 IEEE 标准。
可能是因为它是一个更好的算法。在执行多次舍入的过程中,您将平均得出所有 0.5 的最终舍入均等。例如,如果您要添加一堆四舍五入的数字,这可以更好地估计实际结果。我会说,即使这不是某些人所期望的,但这可能是更正确的做法。
虽然我无法回答“为什么微软的设计师选择这个作为默认设置?”的问题,但我只想指出一个额外的功能是不必要的。
Math.Round
允许您指定 MidpointRounding
:
ToEven - 当一个数字在其他两个数字之间时,它会向最接近的偶数四舍五入。
AwayFromZero - 当一个数字介于其他两个数字之间时,它会朝离零最近的数字四舍五入。
小数主要用于金钱;在处理金钱时,银行家的四舍五入很常见。或者你可以说。
需要十进制类型的主要是银行家;因此它会进行“银行家四舍五入”
银行家四舍五入的优势在于,如果您平均而言,您将获得相同的结果:
在将它们相加之前将一组“发票行”四舍五入,
或将它们相加然后四舍五入
在计算机出现之前的日子里,加起来之前的四舍五入节省了很多工作。
(在英国,当我们采用十进制时,银行不会处理半便士,但多年来仍然存在半便士硬币,而商店的价格通常以半便士结尾——所以很多四舍五入)
Decmial
,是的。小数,没有。对于后人,我同意这里的原始观点。
使用 Round 函数的另一个重载,如下所示:
decimal.Round(2.5m, 0,MidpointRounding.AwayFromZero)
它将输出 3。如果你使用
decimal.Round(2.5m, 0,MidpointRounding.ToEven)
你会得到银行家的四舍五入。