Math.Round()为double产生意外结果

时间:2012-08-28 11:14:40

标签: c# .net double

我在我的代码中偶然发现了一个方法,其中在我的代码中计算了舍入值。 我知道比较双值产生意外结果的问题。

实施例

    double x = 19.08;
    double y = 2.01;
    double result = 21.09;

    if (x + y == result)
    {
        // this is never reached
    }

此处的说明:http://csharpindepth.com/Articles/General/FloatingPoint.aspx

但是,到目前为止,我预计Math.Round()方法即使是双值也是准确的。

看看这段代码。

        var decimals = 2;
        var value1 = 4.725;
        var value2 = 4.725M;

        var result1 = Math.Round(value1, decimals, MidpointRounding.ToEven);
        var result2 = Math.Round(value1, decimals, MidpointRounding.AwayFromZero);
        var result3 = Math.Round(value2, decimals, MidpointRounding.ToEven);
        var result4 = Math.Round(value2, decimals, MidpointRounding.AwayFromZero);

        Console.WriteLine("Double (ToEven): {0}", result1); // outputs 4.72
        Console.WriteLine("Double (AwayFromZero): {0}", result2); // outputs 4.72 (expected: 4.73)
        Console.WriteLine("Decimal (ToEven): {0}", result3); // outputs 4.72
        Console.WriteLine("Decimal (AwayFromZero): {0}", result4); // outputs 4.73

对我来说,结果2应该是4.73是完全清楚的。但事实并非如此。 有人可以解释原因吗?

4 个答案:

答案 0 :(得分:10)

好吧,您可能想重新考虑一下“完全清楚”的概念,因为4.725(而不是4.625)不能double完全表示。它实际上正是

  

4.7249999999999996447286321199499070644378662109375

请记住,浮点数只是实数数学概念的近似值 - 许多关于数字应如何表现的直观概念都不适用。最终得到的值大约 4.725,但显然略低于它。因此,中点舍入模式在此处不执行任何操作,因为它不是两个可能的数字之间的中间点。

答案 1 :(得分:1)

您的value1可能很容易4.724999999999999999999999999999999。为什么要将其四舍五入到4.73而不是4.72

答案 2 :(得分:0)

使用Double值检查相等性时始终存在问题。添加两个双倍值,如0.5 + 0.5,将不会是1.0,但最有可能达到0.99999和1.00001。这与使用浮点数的二进制到十进制的转换有关。

您应该在舍入错误/精度部分检查以下内容: http://www.learncpp.com/cpp-tutorial/25-floating-point-numbers/ 它提供了一些关于浮点精度的有价值的见解,C#也应遵循这个案例。

答案 3 :(得分:0)

使用Convert.ToDouble(value1.ToString(" f2"))而不是Math.Round(value1,2)