为什么 .NET 默认使用银行四舍五入?

发布于 2024-07-09 10:47:16 字数 814 浏览 4 评论 0原文

根据文档, 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

疾风者 2024-07-16 10:47:16

其他答案解释了为什么银行家算法(又名四舍五入)是一个很好的算法选择都非常正确。 它不像从零舍入一半方法那样受到负面或正面偏差的影响超过最合理的分布。

但问题是为什么 .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.

ゃ懵逼小萝莉 2024-07-16 10:47:16

可能是因为这是一个更好的算法。 在执行多次舍入的过程中,您将平均得到所有 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.

恍梦境° 2024-07-16 10:47:16

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

Math.Round 允许您指定 MidpointRounding

  • ToEven - 当一个数字介于另外两个数字之间时,它会向最接近的偶数舍入。
  • AwayFromZero - 当一个数字介于另外两个数字之间时,它会向远离零的最接近的数字舍入。

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 a MidpointRounding:

  • ToEven - When a number is halfway between two others, it is rounded toward the nearest even number.
  • AwayFromZero - When a number is halfway between two others, it is rounded toward the nearest number that is away from zero.
感情废物 2024-07-16 10:47:16

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

主要是银行家需要
小数类型; 因此它确实
“银行四舍五入”

银行家四舍五入的优点是,平均而言,如果您执行以下操作,您将得到相同的结果:

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

在相加之前四舍五入可以节省大量成本在计算机出现之前的日子里工作。

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

Decimals are mostly used for money; banker’s rounding is common when working with money. Or you could say.

It is mostly bankers that need the
decimal type; therefore it does
“banker’s rounding”

Bankers rounding have the advantage that on average you will get the same result if you:

  • round a set of “invoice lines” before adding them up,
  • or add them up then round the total

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)

云朵有点甜 2024-07-16 10:47:16

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

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

它将输出 3。 如果您使用,

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

您将获得银行家的四舍五入。

Use another overload of Round function like this:

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

It will output 3. And if you use

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

you will get banker's rounding.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文