5

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

例子

    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

对我来说,result2 应该是 4.73 是完全清楚的。然而,事实并非如此。有人可以解释为什么吗?

4

4 回答 4

10

好吧,您可能需要重新考虑您的“完全清楚”的概念,因为 4.725(相对于 4.625)不能double. 实际上正是

4.7249999999999996447286321199499070644378662109375

请记住,浮点数只是对实数的数学概念的近似——许多关于数字应该如何表现的直观概念并不适用。您最终得到的值大约为 4.725,但显然略低于它。因此,中点舍入模式在这里不会做任何事情,因为它并不完全位于两个可能要舍入的数字之间。

于 2012-08-28T11:17:47.740 回答
1

value1很容易成为4.724999999999999999999999999999999。为什么要四舍五入 to4.73而不是4.72

于 2012-08-28T11:17:38.597 回答
0

在检查 Double 值是否相等时总是会出现问题。添加两个像 0.5 + 0.5 这样的双精度值不会是 1.0,但很可能最终会是 0.99999 和 1.00001。这与使用浮点数从二进制到十进制的转换有关。

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

于 2012-08-28T11:19:05.450 回答
0

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

于 2014-08-21T09:28:50.430 回答