8

我知道这已经被一次又一次地讨论过,但我似乎无法得到一个最简单的例子,即一步除法的双打结果在 C# 中产生预期的、未舍入的结果——所以我想知道是否可能即有一些编译器标志或其他我没有想到的奇怪的东西。考虑这个例子:

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

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

4

6 回答 6

19

Is it not strange that two low-precision doubles like this can't divide to the correct value of 28?

No, not really. Neither 0.7 nor 0.025 can be exactly represented in the double type. The exact values involved are:

0.6999999999999999555910790149937383830547332763671875
0.025000000000000001387778780781445675529539585113525390625

Now are you surprised that the division doesn't give exactly 28? Garbage in, garbage out...

As you say, the right result to represent decimal numbers exactly is to use decimal. If the rest of your program is using the wrong type, that just means you need to work out which is higher: the cost of getting the wrong answer, or the cost of changing the whole program.

于 2012-05-04T07:20:44.890 回答
6

精度始终是一个问题,以防您处理floator double

它是计算机科学中的一个已知问题,每种编程语言都受到它的影响。为了最大限度地减少这些主要与舍入有关的错误,一个完整的数值分析领域专门用于它。

例如,让我们看下面的代码。

你会期待什么?

你会期望答案是1,但事实并非如此,你会得到0.9999907

        float v = .001f;            
        float sum = 0;
        for (int i = 0; i < 1000; i++ )
        {
            sum += v;
        }
于 2012-05-04T07:37:47.930 回答
4

It has nothing to do with how 'simple' or 'small' the double numbers are. Strictly speaking, neither 0.7 or 0.025 may be stored as exactly those numbers in computer memory, so performing calculations on them may provide interesting results if you're after heavy precision.

So yes, use decimal or round.

于 2012-05-04T07:20:51.583 回答
4

以此类推:

假设您在以 3 为基数工作。在以 3 为基数的情况下,0.1 是(十进制)1/3,或 0.333333333'。

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

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

于 2012-05-04T07:58:12.470 回答
2

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

于 2012-05-04T07:22:13.637 回答
2

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

有一整个数学领域称为数值分析,它基本上处理在使用这种近似值时如何最小化错误。

于 2012-05-04T07:21:44.347 回答