为什么这个循环永远不会结束?

Tru*_* Ha 19 floating-point ieee-754

可能重复:
比较C#中的double值时出现问题

我在其他地方读过它,但是真的忘记了答案,所以我再次问这里.无论你用任何语言编写它,我都不会结束这个循环(我用C#,C++,Java测试它):

double d = 2.0;
while(d != 0.0){
   d = d - 0.2;
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 32

浮点计算不是很精确.您将得到一个表示错误,因为0.2没有精确表示为二进制浮点数,因此该值不会完全等于零.尝试添加调试语句以查看问题:

double d = 2.0;
while (d != 0.0)
{
    Console.WriteLine(d);
    d = d - 0.2;
}
Run Code Online (Sandbox Code Playgroud)
2
1,8
1,6
1,4
1,2
1
0,8
0,6
0,4
0,2
2,77555756156289E-16   // Not exactly zero!!
-0,2
-0,4

解决它的一种方法是使用类型decimal.


Jon*_*eet 27

(有一件事你并没有使用相同的变量,但我会认为这是一个错字:)

0.2不是0.2.它是最接近double0.2的值.当你减去的10倍,从2.0,你就不会结了正好 0.0.

在C#中,您可以更改为使用decimal类型,这将起作用:

// Works
decimal d = 2.0m;
while (d != 0.0m) {
   d = d - 0.2m;
}
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为十进制类型确实表示精确到0.2的十进制值(在限制范围内;它是128位类型).所涉及的每一个价值都是精确可表现的,因此它起作用 什么行不通的将是这样的:

decimal d = 2.0m;
while (d != 0.0m) {
   d = d - 1m/3m;
}
Run Code Online (Sandbox Code Playgroud)

在这里,"第三个"并不完全可以表示,所以我们最终遇到了和以前一样的问题.

但总的来说,在浮点数之间进行精确的相等比较是个坏主意 - 通常你会在一定的容差范围内对它们进行比较.

我有关于从C#/ .NET上下文浮动二进制点浮点小数点的文章,它们更详细地解释了一些事情.


小智 11

我记得买了一个Sinclair ZX-81,通过优秀的Basic编程手册,当我遇到第一个浮点舍入错误时,几乎回到了商店.

我永远不会想到人们在27.99998年之后仍然会遇到这些问题.

  • +1为27.99998年:-) (7认同)
  • ZX-Spectrum手册附带了对此问题的详细说明.我记得很难(在大约10岁或11岁时)并且去"哦,这是有道理的".这是一本非常好的手册...... (2认同)