划分双打时C#精度损失

时间:2012-05-04 07:12:54

标签: c# double precision

我知道这已经被一次又一次地讨论过,但我似乎无法得到一个一步一步的双重划分的最简单的例子,导致C#中预期的,不完整的结果 - 所以我是想知道是否有一些编译器标志或其他奇怪的东西,我没想到。考虑这个例子:

double v1 = 0.7;
double v2 = 0.025;
double result = v1 / v2;

当我在最后一行之后断开并在VS调试器中检查它时,“result”的值是27.999999999999996。我知道我可以通过更改为“十进制”来解决它,但在周围程序的情况下这是不可能的。像这样的两个低精度双倍不能分成28的正确值是不奇怪的? Math.Round是唯一真正解决结果的解决方案吗?

6 个答案:

答案 0 :(得分:17)

  

像这样的两个低精度双打不能分成28的正确值这并不奇怪吗?

不,不是真的。在double类型中,0.7和0.025都不能精确表示。涉及的确切值是:

0.6999999999999999555910790149937383830547332763671875
0.025000000000000001387778780781445675529539585113525390625

现在你觉得这个部门没有准确地给出28分吗?垃圾进去,垃圾出来......

正如您所说,正确表示十进制数字的正确结果是使用decimal。如果你的程序的其余部分使用了错误的类型,那只意味着你需要解决更高的问题:获得错误答案的成本,或者改变整个程序的成本。

答案 1 :(得分:4)

它与double数字的“简单”或“小”无关。严格地说,0.70.025都不能完全存储在计算机内存中,因此如果您精确度较高,则对其进行计算可能会提供有趣的结果。

是的,请使用decimal或圆形。

答案 2 :(得分:4)

如果您正在处理floatdouble,精确度始终是个问题。

它是计算机科学中的一个已知问题,每种编程语言都受其影响。为了最大限度地减少这些与舍入主要相关的错误,Numerical Analysis的完整字段专用于它。

例如,让我们采取以下代码。

你会期待什么?

您希望答案为1,但事实并非如此,您将获得0.9999907

        float v = .001f;            
        float sum = 0;
        for (int i = 0; i < 1000; i++ )
        {
            sum += v;
        }

答案 3 :(得分:4)

通过类比来解释:

想象一下你在基地3工作。在基数3中,0.1是(十进制)1/3,或0.333333333'。

因此,您可以在基数3中精确表示1/3(十进制),但在尝试以十进制表示时会出现舍入错误。

嗯,你可以用一些十进制数得到完全相同的东西:它们可以用十进制精确表示,但它们不能用二进制精确表示;因此,你会得到它们的舍入错误。

答案 4 :(得分:2)

对第一个问题的简短回答:不,这并不奇怪。浮点数是实数的离散近似值,这意味着当您进行算术运算时,舍入误差将传播和缩放。

Theres'是一个完整的数学领域,称为数值分析,主要处理如何在使用这种近似值时最小化误差。

答案 5 :(得分:2)

这是通常的浮点不精确。并非每个数字都可以表示为double,并且这些次要表示不准确性会加起来。这也是你不应该将双打与精确数字进行比较的原因。我刚刚对其进行了测试,result.ToString()显示28(可能会在double.ToString()中进行某种舍入?)。 result == 28已返回false。并(int)result返回27。所以你只需要期待那样的不精确。