为什么Math.Round(2.5)返回2而不是3?

jef*_*ffu 388 .net rounding

在C#中,结果Math.Round(2.5)为2.

应该是3,不是吗?为什么它是2而不是C#?

Jon*_*eet 537

首先,这不会是一个C#错误 - 它将是一个.NET错误.C#是语言 - 它不决定如何Math.Round实现.

其次,不 - 如果你阅读文档,你会看到默认的舍入是"舍入到均匀"(银行家的舍入):

返回值
类型:System.Double
最接近a的整数.如果a的小数分量在两个整数之间,其中一个是偶数而另一个是奇数,则返回偶数.请注意,此方法返回Double而不是整数类型.

备注
此方法的行为遵循IEEE标准754第4节.这种舍入有时称为舍入到最近,或者是银行家的舍入.它最大限度地减少了在单个方向上始终舍入中点值所导致的舍入误差.

您可以指定如何Math.Round使用带有值的重载来舍入中点MidpointRounding.有一个重载与MidpointRounding每个重载相对应,没有一个:

是否选择此默认值是另一回事.(MidpointRounding仅在.NET 2.0中引入.在此之前我不确定是否有任何简单的方法来实现所需的行为而不自己做.)特别是,历史表明它不是预期的行为 - 并且在大多数情况下是API设计中的主要罪恶.我可以看出为什么 Banker的Rounding很有用......但对许多人来说仍然是一个惊喜.

您可能有兴趣查看最近的Java等效枚举(RoundingMode),它提供了更多选项.(它不只是处理中点.)

  • +1"这不是预期的行为[...],这是API设计中的一个主要罪过" (24认同)
  • 实际上,IEEE标准754第4节作为文档陈述. (7认同)
  • 我不知道这是一个错误,我认为它是设计的,因为.5接近最接近的最小整数,因为它是最接近的最高整数. (4认同)
  • 在.NET应用之前,我记得VB中的这种行为. (3认同)
  • 我不久前被这个烧了,认为这也是纯粹的疯狂.幸运的是,他们增加了一种方法来指明我们所有人在小学时学到的四舍五入; MidPointRounding. (2认同)

pax*_*blo 200

这被称为舍入到均匀(或银行家的舍入),这是一种有效的舍入策略,用于最小化累积的总和错误(MidpointRounding.ToEven).理论上说,如果你总是在同一方向上绕0.5的数字,那么错误会更快地产生(圆形到偶数应该最小化)(a).

请按照以下链接获取MSDN描述:

  • Math.Floor,向负无穷大向下舍入.
  • Math.Ceiling,向正无穷大方向前进.
  • Math.Truncate,向上或向下舍入为零.
  • Math.Round,舍入到最接近的整数或指定的小数位数.如果它在两种可能性之间完全等距,则可以指定行为,例如舍入以使最后一位数为偶数(" Round(2.5,MidpointRounding.ToEven)"变为2)或者使其远离零(" Round(2.5,MidpointRounding.AwayFromZero)"变为3).

以下图表和表格可能会有所帮助:

-3        -2        -1         0         1         2         3
 +--|------+---------+----|----+--|------+----|----+-------|-+
    a                     b       c           d            e

                       a=-2.7  b=-0.5  c=0.3  d=1.5  e=2.8
                       ======  ======  =====  =====  =====
Floor                    -3      -1      0      1      2
Ceiling                  -2       0      1      2      3
Truncate                 -2       0      0      1      2
Round(ToEven)            -3       0      0      2      3
Round(AwayFromZero)      -3      -1      0      2      3
Run Code Online (Sandbox Code Playgroud)

请注意,Round它比看起来更强大,只是因为它可以舍入到特定的小数位数.所有其他的总是小数点零.例如:

n = 3.145;
a = System.Math.Round (n, 2, MidpointRounding.ToEven);       // 3.14
b = System.Math.Round (n, 2, MidpointRounding.AwayFromZero); // 3.15
Run Code Online (Sandbox Code Playgroud)

使用其他函数,您必须使用乘法/除法技巧来实现相同的效果:

c = System.Math.Truncate (n * 100) / 100;                    // 3.14
d = System.Math.Ceiling (n * 100) / 100;                     // 3.15
Run Code Online (Sandbox Code Playgroud)

(a)当然,这个理论取决于你的数据在偶数半部分(0.5,2.5,4.5,......)和奇数半部分(1.5,3.5,......)之间具有相当均匀的值.

如果所有 "半值"都是平均值(例如),则错误将像您总是向上舍入一样快地累积.

  • 也被称为银行家的舍入 (3认同)

Mic*_*tta 42

MSDN,Math.Round(double a)返回:

最接近a的整数.如果a的小数分量在两个整数之间,其中一个是偶数而另一个是奇数,则返回偶数.

......等于2.5,介于2和3之间,向下舍入到偶数(2).这被称为Banker's Rounding(或round-to-even),是一种常用的舍入标准.

相同的MSDN文章:

此方法的行为遵循IEEE标准754第4节.这种舍入有时称为舍入到最近,或者是银行家的舍入.它最大限度地减少了在单个方向上始终舍入中点值所导致的舍入误差.

您可以通过调用采用MidpointRounding模式的Math.Round重载来指定不同的舍入行为.


Dir*_*mar 37

你应该检查MSDN Math.Round:

此方法的行为遵循IEEE标准754第4节.这种舍入有时称为舍入到最近,或者是银行家的舍入.

您可以指定Math.Round使用重载的行为:

Math.Round(2.5, 0, MidpointRounding.AwayFromZero); // gives 3

Math.Round(2.5, 0, MidpointRounding.ToEven); // gives 2
Run Code Online (Sandbox Code Playgroud)


Pat*_*ers 31

四舍五入的性质

考虑将包含分数的数字四舍五入到整数的任务.在这种情况下舍入的过程是确定哪个整数最能代表你正在舍入的数字.

通常,或"算术"舍入,很明显2.1,2.2,2.3和2.4舍入到2.0; 和2.6,2.7,2.8和2.9到3.0.

离开2.5,它不接近2.0而不是3.0.您可以在2.0和3.0之间进行选择,两者都同样有效.

对于负数,-2.1,-2.2,-2.3和-2.4,将变为-2.0; 在算术舍入下,-2.6,2.7,2.8和2.9将变为-3.0.

对于-2.5,需要在-2.0和-3.0之间进行选择.

其他形式的舍入

'Rounding up'取任意小数位数,并使其成为下一个'整数'.因此,不仅2.5和2.6轮到3.0,而2.1和2.2也是如此.

四舍五入将正数和负数从零开始移动.例如.2.5至3.0和-2.5至-3.0.

'舍入'通过砍掉不需要的数字来截断数字.这具有将数字移向零的效果.例如.2.5至2.0和-2.5至-2.0

在"银行家的舍入"中 - 以其最常见的形式 - 要舍入的.5向上或向下舍入,以便舍入的结果始终为偶数.因此2.5轮到2.0,3.5到4.0,4.5到4.0,5.5到6.0,依此类推.

'替代舍入'在舍入和舍入之间交替任何.5的过程.

"随机舍入"在完全随机的基础上向上或向下舍入.5.

对称性和不对称性

如果舍入函数将所有数字舍入为零或将所有数字舍入为零,则称舍入函数为"对称".

如果将正数向零舍入,而将负数向零舍入,则函数为"非对称".例如.2.5到2.0; 和-2.5到-3.0.

非对称性是将正数从零和负数向零舍入的函数.例如.2.5至3.0; 和-2.5到-2.0.

大多数时候人们会想到对称的舍入,其中-2.5将向-3.0舍入,3.5将向4.0舍入.(在C#中Round(AwayFromZero))


Chr*_*s S 25

默认情况下MidpointRounding.ToEven,或者银行家的四舍五入(2.5变成2,4.5变成4等等)之前我已经在写会计报告时惹我生气了所以我会写一些关于我之前发现的内容并且从中查找这个帖子.

谁是这些银行家,甚至是数字(英国银行家!)?

来自维基百科

银行家四舍五入这一术语的起源仍然较为模糊.如果这种舍入方法曾经是银行业的标准,那么事实证明很难找到证据.相反,欧盟委员会报告"欧元的引入和货币数量的四舍五入"第2节表明,以前没有标准的方法来进行银行业务的四舍五入; 并指明应将"中途"金额四舍五入.

这似乎是一种非常奇怪的四舍五入的方式,尤其是银行业务,除非银行当然会用来接收大量的偶数存款.存款240万英镑,但我们称之为200万英镑.

IEEE标准754可以追溯到1985年,它提供了两种舍入方式,但是银行家是标准推荐的方式.这篇维基百科文章有很长的列表,列出了语言如何实现舍入(如果下面的任何一个错误,请纠正我),大多数不使用银行家,但是你在学校教授的四舍五入:

  • 来自math.h的C/C++ round()从零开始(不是银行家的舍入)
  • Java Math.Round从零开始舍入(它将结果置于底层,添加0.5,转换为整数).BigDecimal中有另一种选择
  • Perl使用与C类似的方式
  • Javascript与Java的Math.Round相同.


小智 15

来自MSDN:

默认情况下,Math.Round使用MidpointRounding.ToEven.大多数人不熟悉"四舍五入"作为替代方案,"从零开始四舍五入"更常见于学校..NET默认为"舍入到均匀",因为它在统计上更优越,因为它不会分享"从零舍入"的趋势,而是比向下舍入更频繁地舍入(假设舍入的数字往往是正数). )

http://msdn.microsoft.com/en-us/library/system.math.round.aspx