Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Math.Round()为double生成意外的结果_C#_.net_Double - Fatal编程技术网

C# Math.Round()为double生成意外的结果

C# Math.Round()为double生成意外的结果,c#,.net,double,C#,.net,Double,我在代码中偶然发现了一个方法,其中舍入值在代码中计算错误。 我知道比较双值会产生意外结果的问题 范例 double x = 19.08; double y = 2.01; double result = 21.09; if (x + y == result) { // this is never reached } 解释如下: 然而,直到现在,我仍然希望Math.Round()方法即使使用双值也是准确的 看看这个代码

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

范例

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

    if (x + y == result)
    {
        // this is never reached
    }
解释如下:

然而,直到现在,我仍然希望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是完全清楚的。然而,事实并非如此。
有人能解释一下原因吗?

您的
值1
很可能是
4.7249999999999999999999999
。为什么要将它四舍五入到
4.73
而不是
4.72

好吧,你可能需要重新思考你的“完全清楚”的概念,因为4.725(相对于4.625)不能用
双精度表示。实际上正是

4.724999999969447286321199499070644378662109375


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

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

您应在舍入误差/精度部分检查以下读数:
它为浮点精度提供了一些有价值的见解,C#也应该遵循这种情况。

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

+1对我来说,这是最后一句话,它使这成为最佳答案+1。如果OP混淆了为什么它是代码>4.7249999999999996 < /代码>,他们应该考虑将1/3精确地写为十进制数。当然他们不能,他们从
0.3333
开始,一直走到累了或空间不够为止
double
对二进制的
4725/1000
执行的操作与十进制的
1/3
相同。它做得最好,但是在
4.724999999999996447286321199499070644378662109375之后,它的空间就用完了。是的,有些我们可以用更大的数据类型进行完全精确(如果没有至少5位尾数,我们也不能用十进制进行12345/10000精确运算),有些数字无论大小都是不可能的——就像十进制的1/3。我知道不是每个十进制数字都可以用双精度表示。我的问题更像是
为什么Math.Round(…)
没有考虑到这一点?因为,如果我将我的双精度转换为十进制,然后进行
数学.Round(…)
运算,结果是4.73。@Schlaviener对Round的调用不知道您键入了
4.72
,它知道您要对
4.72499999999999994472863211994990704378662109375
。对于所有的方法来说,你输入了它的每一个数字(或者从另一个来源获得了它的每一个数字)。结果4真的输出了4.72吗?结果4显示了4.73。随它去吧,但双重听起来有点奇怪。拉杰,绝对不是。事实上,这正是您所期望的。对不起,复制粘贴;)结果4为4.73,与预期的不一样。您对ToString()如何舍入值没有影响。