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

481

在C#中,Math.Round(2.5)的结果是2。

这不应该是3吗?为什么在C#中结果却是2呢?


7
这实际上是一项功能。请参阅<a href="http://msdn.microsoft.com/en-us/library/3s2d3xkk(VS.80).aspx">MSDN文档</a>。这种取整方式称为“银行家舍入法”。至于解决方法,有<a href="http://msdn.microsoft.com/en-us/library/ms131274(VS.80).aspx">一个重载</a>允许调用者指定如何进行取整。 - Joe
1
显然,当要求将一个数字精确地四舍五入到两个整数之间时,round方法会返回偶数。因此,Math.Round(3.5)返回4。请参阅此文章:http://msdn.microsoft.com/en-us/library/3s2d3xkk.aspx - Matthew Jones
36
Math.Round(2.5, 0, MidpointRounding.AwayFromZero); - Robert Durgin
10
@amed 这不是一个 bug,这是二进制浮点数的工作方式。“1.005” 无法在双精度下准确表示。它可能是“1.00499...”。如果使用 Decimal 类型,这个问题就会消失。在我的看法中,Math.Round 方法重载,以双精度数字的小数位数为参数,是一个值得怀疑的设计选择,因为它很少能够有效地工作。 - CodesInChaos
@ColeJohnson:IEEE规定四舍五入到偶数。由于它可以被准确地表示,因此应用了这个规则。 - leppie
显示剩余6条评论
15个回答

0

Silverlight不支持MidpointRounding选项。 这里是一个为Silverlight添加MidpointRounding枚举的扩展方法:

public enum MidpointRounding
{
    ToEven,
    AwayFromZero
}

public static class DecimalExtensions
{
    public static decimal Round(this decimal d, MidpointRounding mode)
    {
        return d.Round(0, mode);
    }

    /// <summary>
    /// Rounds using arithmetic (5 rounds up) symmetrical (up is away from zero) rounding
    /// </summary>
    /// <param name="d">A Decimal number to be rounded.</param>
    /// <param name="decimals">The number of significant fractional digits (precision) in the return value.</param>
    /// <returns>The number nearest d with precision equal to decimals. If d is halfway between two numbers, then the nearest whole number away from zero is returned.</returns>
    public static decimal Round(this decimal d, int decimals, MidpointRounding mode)
    {
        if ( mode == MidpointRounding.ToEven )
        {
            return decimal.Round(d, decimals);
        }
        else
        {
            decimal factor = Convert.ToDecimal(Math.Pow(10, decimals));
            int sign = Math.Sign(d);
            return Decimal.Truncate(d * factor + 0.5m * sign) / factor;
        }
    }
}

来源:http://anderly.com/2009/08/08/silverlight-midpoint-rounding-solution/


0

.NET四舍五入具有您正在寻找的答案。

基本上它说:

返回值

最接近数字且精度等于digits的值。如果value恰好位于两个数字之间,其中一个是偶数,另一个是奇数,则返回偶数。 如果value的精度小于digits,则返回未更改的value。

此方法的行为遵循IEEE标准754第4节。这种舍入有时称为最近舍入或银行家舍入。如果digits为零,则有时称为朝零舍入。


-1
使用自定义的四舍五入。
public int Round(double value)
{
    double decimalpoints = Math.Abs(value - Math.Floor(value));
    if (decimalpoints > 0.5)
        return (int)Math.Round(value);
    else
        return (int)Math.Floor(value);
}

>.5 产生与 Math.Round 相同的行为。问题是当小数部分恰好为 0.5 时会发生什么。Math.Round 允许您指定所需的舍入算法。 - Panagiotis Kanavos

-2

这是我不得不解决它的方法:

Public Function Round(number As Double, dec As Integer) As Double
    Dim decimalPowerOfTen = Math.Pow(10, dec)
    If CInt(number * decimalPowerOfTen) = Math.Round(number * decimalPowerOfTen, 2) Then
        Return Math.Round(number, 2, MidpointRounding.AwayFromZero)
    Else
        Return CInt(number * decimalPowerOfTen + 0.5) / 100
    End If
End Function

尝试使用2位小数的1.905将得到预期的1.91,但是Math.Round(1.905,2,MidpointRounding.AwayFromZero)却给出了1.90!Math.Round方法在大多数程序员可能遇到的基本问题中是绝对不一致和无法使用的。我必须检查(int) 1.905 * decimalPowerOfTen = Math.Round(number * decimalPowerOfTen, 2)是否会导致我不想四舍五入的向下取整。


1
Math.Round(1.905,2,MidpointRounding.AwayFromZero) returns 1.91 - Panagiotis Kanavos

-3

这很丑陋,但总是产生正确的算术舍入。

public double ArithRound(double number,int places){

  string numberFormat = "###.";

  numberFormat = numberFormat.PadRight(numberFormat.Length + places, '#');

  return double.Parse(number.ToString(numberFormat));

}

5
调用Math.Round并指定所需的舍入方式,可以实现四舍五入。 - configurator

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接