283

根据文档,该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的初学者来说,这可能会产生误导。

4

5 回答 5

447

其他解释为什么银行家的算法(又名四舍五入到偶数)是一个不错的选择的原因是非常正确的。在最合理的分布上,它不会像零差一半方法那样受到负偏或正偏的影响。

但问题是 .NET 为什么默认使用 Banker 的实际舍入 - 答案是 Microsoft 遵循IEEE 754标准。这也在MSDN for Math.Round的备注下提到。

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

于 2011-07-03T09:09:41.327 回答
206

可能是因为它是一个更好的算法。在执行多次舍入的过程中,您将平均得出所有 0.5 的最终舍入均等。例如,如果您要添加一堆四舍五入的数字,这可以更好地估计实际结果。我会说,即使这不是某些人所期望的,但这可能是更正确的做法。

于 2008-11-22T19:57:14.757 回答
89

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

Math.Round允许您指定MidpointRounding

  • ToEven - 当一个数字在其他两个数字之间时,它会向最接近的偶数四舍五入。
  • AwayFromZero - 当一个数字介于其他两个数字之间时,它会朝离零最近的数字四舍五入。
于 2008-11-22T19:59:54.330 回答
22

小数多用于金钱;在处理金钱时,银行家的四舍五入很常见。或者你可以说。

需要十进制类型的主要是银行家;因此它会进行“银行家四舍五入”</p>

银行家四舍五入的优势在于,如果您平均而言,您将获得相同的结果:

  • 在将它们相加之前将一组“发票行”四舍五入,
  • 或将它们相加然后四舍五入

在计算机出现之前的日子里,加起来之前的四舍五入节省了很多工作。

(在英国,当我们采用十进制时,银行不会处理半便士,但多年来仍然存在半便士硬币,而商店的价格通常以半便士结尾——所以很多四舍五入)

于 2010-01-22T12:58:04.503 回答
0

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

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

它将输出3。如果你使用

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

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

于 2017-03-26T14:44:22.177 回答