为什么Convert.ToInt32()舍入到最接近的偶数,而不是最接近的整数?

查看Convert.ToInt32()的msdn文档,它指出:

如果值在两个整数之间,则返回偶数; 也就是说,4.5转换为4,5.5转换为6。

http://msdn.microsoft.com/en-us/library/ffdk7eyz.aspx

为什么是这样?

当然,舍入到最接近的整数更合乎逻辑,不是吗? 如果是这样,4.5将变为5,而5.5将变为6,这似乎更直观。

Rounding维基百科条目的历史部分有一些关于计算中“round to even”的作用的陈述。 有趣的是,看起来“Bankers Rounding”几乎没有证据表明它在任何意义上都是官方的,因此只能用作俚语术语。

如果您订阅该舍入机制,那只是“更合乎逻辑”。 四舍五入(在这种情况下是默认值)也是完全符合逻辑的。

想象一下,如果银行的每一小部分金额都汇总到最接近的便士,那么每天处理的数百万交易将会减少很多(对于愤世嫉俗的人而言)损失很多钱。 好的,所以这个例子是愤世嫉俗的。

走向最接近的偶数(或奇数,但历史选择否则)意味着并非每个舍入分辨率都会上升有些可能会下降 。 当你把它放到平均律时,在考虑负责支付额外的半便士时,它就成了一个公平的解决方案。

至于为什么选择这个框架,这个问题试图解决它:

为什么.NET使用银行家的舍入作为默认值?

当然,这一切都可以追溯到金融时代,它对整数的适用性可能会受到质疑,但为什么还要烦恼呢? 接受它,如果你愿意,可以覆盖它,只要了解它是如何工作的。


对于想知道如何更改默认舍入的人:

如果你要为Convert.ToInt32提供一个非整数,你首先需要做一些像Convert.ToDoubleMath.Round的重载来改变舍入逻辑 。

这正是MidpontRounding重载被添加到Math.Round

因此,为了正确舍入,您应该使用Math.Round而不是Convert.ToInt32。

不考虑MidpointRounding.ToEven(Banker的舍入)或MidpointRounding.AwayFromZero的主观问题是否会更好。

在设计时,微软会考虑.NET旨在取代的语言。

  • VB classic默认使用Banker的Rounding。

  • C / C ++转换在转换时截断,并且在运行时库中具有库函数floor()和ceil() – 但是(AFAIK,可能是错误的)没有循环函数。

  • Java有一个Math.round, 在文档中被描述为等同于Math.round(a + 0.5)。 这可能不是大多数人所期望的负数(-3.5轮到-3)。

  • 可以说,VB开发人员可能需要比来自C / C ++或Java的开发人员更多的手持操作。

因此,在设计.NET时,类库将提供FloorCeilingRound方法,并且Round行为将默认为VB的行为,这似乎是合理的。

Convert.ToInt32()使用Round方法似乎也是合理的(虽然我想可以为Floor做一个案例,以便与cast一致)。

如果您想要这种行为,则需要使用Math.Round并指定MidpointRounding.AwayFromZero

例如:

 int result = (int)Math.Round(4.5, MidpointRounding.AwayFromZero); 

演示: http : //ideone.com/ZAbBL

Convert.ToInt32(double)不使用Math.Round本身,而是以这种方式实现(ILSpy):

 public static int ToInt32(double value) { if (value >= 0.0) { if (value < 2147483647.5) { int num = (int)value; double num2 = value - (double)num; if (num2 > 0.5 || (num2 == 0.5 && (num & 1) != 0)) { num++; } return num; } } else { if (value >= -2147483648.5) { int num3 = (int)value; double num4 = value - (double)num3; if (num4 < -0.5 || (num4 == -0.5 && (num3 & 1) != 0)) { num3--; } return num3; } } throw new OverflowException(Environment.GetResourceString("Overflow_Int32")); }