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

时间:2012-07-11 11:35:55

标签: c# decimal rounding int32

查看Convert.ToInt32()的msdn文档,它声明:

  

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

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

为什么会这样?

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

4 个答案:

答案 0 :(得分:11)

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

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

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

走向最近的偶数(或奇数,但历史选择其他方式)意味着并非每个舍入分辨率上升有些现在可以向下 < / strong>即可。当你把这个放到平均律时,当考虑 负责支付额外的半便士时,它就成了一个公平的解决方案。

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

Why does .NET use banker's rounding as default?

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

<小时/> 对于想知道如何更改默认舍入的人:

如果您向Convert.ToInt32提供非整数,则首先需要执行Convert.ToDouble然后Math.Round with the overload to change the rounding logic之类的操作。

答案 1 :(得分:3)

这就是为MidpontRounding添加Math.Round重载的原因。

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

答案 2 :(得分:3)

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

在设计时,微软会考虑使用.NET设计替代的语言。

  • VB classic默认使用Banker的舍入。

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

  • Java有一个Math.round,in the documentation被描述为等同于Math.round(a + 0.5)。这可能不是大多数人对负数的预期(-3.5轮到-3)。

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

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

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

答案 3 :(得分:1)

如果您需要这种行为,则需要使用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"));
}