C++中的for循环使用双重提前一步,未达到边界值

5 c++ for-loop floating-accuracy

我在32位Ubuntu 8.04上使用gcc 4.2.4编译了一个简单的C++程序.它有一个for-loop,其中一个double变量从零增加到一个具有一定步长的一个.当步长是0.1,行为是我所期望的.但是当步长为'0.05'时,循环退出0.95.谁能告诉我为什么会这样?输出遵循以下源代码.

#include <iostream>

using namespace std;

int main()
{
    double rangeMin = 0.0;
    double rangeMax = 1.0;
    double stepSize = 0.1;

    for (double index = rangeMin; index <= rangeMax; index+= stepSize)
    {
        cout << index << endl;
    }
    cout << endl; 

    stepSize = 0.05;
    for (double index = rangeMin; index <= rangeMax; index+= stepSize)
    {
        cout << index << endl;
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

OUTPUT

sarva@savija-dev:~/code/scratch$ ./a.out 
0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1

0
0.05
0.1
0.15
0.2
0.25
0.3
0.35
0.4
0.45
0.5
0.55
0.6
0.65
0.7
0.75
0.8
0.85
0.9
0.95
sarva@savija-dev:~/code/scratch$
Run Code Online (Sandbox Code Playgroud)

Mot*_*tti 18

使用浮点值时,并非每个值都可以准确表示,0.95+0.05 > 1因为0.95值不能完全表示double.

了解维基百科对浮点精度的看法.

如果你看一下IEEE浮点转换器,你会看到0.9564位浮点(double)的值是0-01111111110-1110011001100110011001100110011001100110011001100110通过在浮点计算器中输入这个值得到的值,0.95000016并且加上0.05它会超过1.0标记.

这就是为什么你不应该在循环中使用浮点(或者更一般地将浮点计算的结果与精确值进行比较).


Ann*_*nna 11

通常,当你比较双打时,简单的比较不够好,你应该比较它们"达到精度".即:

if ( fabs(double1-double2) < 0.0000001 ) {
  do-something
}
Run Code Online (Sandbox Code Playgroud)

由于双变量表示,会出现问题.


Kir*_*sky 6

由于其内部表示,您不应使用==或<=表示双精度数.在最后一步,你会得到0.95000000000000029.相反,您可以使用以下代码:

stepSize = 0.05;
// stepSize/2 looks like a good delta for most cases
for (double index = rangeMin; index < rangeMax+stepSize/2; index+= stepSize)
{
    cout << index << endl;
}
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请阅读每位计算机科学家应该了解的关于浮点运算的内容.


Ant*_*ano 6

正如其他人所提到的,由于内存中某些十进制数的不精确表示,这是一个众所周知的问题.我强烈建议阅读每个计算机科学家应该知道的浮点运算实数的IEEE浮点表示.