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

Jür*_*ock 5 .net c# double

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

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

    if (x + y == result)
    {
        // this is never reached
    }
Run Code Online (Sandbox Code Playgroud)

这里的解释:http://csharpindepth.com/Articles/General/FloatingPoint.aspx

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

看看这段代码.

        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
Run Code Online (Sandbox Code Playgroud)

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

Joe*_*oey 10

好吧,你可能想重新思考一下你完全清楚的概念,因为4.725(而不是4.625)不能用a表示double.它实际上是完全正确的

4.7249999999999996447286321199499070644378662109375

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

  • +1.如果OP对于为什么这是"4.7249999999999996"感到困惑,他们应该考虑将1/3精确地写为十进制数.当然他们不能,他们从`0.3333333333`开始并继续前进直到他们累了或用完了空间.`double`用二进制的`4725/1000`做同样的事情,就像十进制的`1/3`一样.它确实是最好的,但在"4.7249999999999996447286321199499070644378662109375"之后,它的空间不足. (3认同)