#include <iostream>
int main()
{
double i = 0;
while(i < 1)
{
std::cout << i << std::endl;
i += 0.1;
}
return 0;
}
运行结果:
0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1
问题:当 i 为1时不符合 while循环中 i < 1 的不等式,为何还会进入循环中输出 1 呢?
浮点数的精度问题,浮点数在计算机中存储是使用 [IEEE 754](https://baike.baidu.com/item/IEEE%20754/3869922) 标准进行存储的。在使用浮点数进行比较时会存在一个精度问题。
下面我们使用vs自带的调试功能来看一下while循环里发生了什么事情。当i为0时,执行了 i+=0.1后它的值并不是 0.1 而是下图中所显示的 0.1000000001 。
而在我们最后一次循环时,i的值并不是我们想象的为 1, 而是一个近似为1的值 0.9999999999 。因此在下一次比较时会继续的进入循环体内。
我们可以尝试修改程序,使用printf函数的格式化输出,打印出 i 中存储的原数据。
解决浮点数精度比较的办法也非常简单,在林锐的《高质量 C++/C 编程指南》一书中提到不能将浮点数与整数直接进行比较,(截图如下)
解决的办法就是,设置一个精度范围,在此精度范围内我们认为是相等的。
假设有浮点数 a 与 浮点数 b 比较是否相等( a == b,?),我们换个角度想,两数相等则他们的差必为0 。则原式等于判断 a-b == 0 。我们设置一个误差精度为0.01,则在此精度之内的数都可认为与0相等。如下图所示,在蓝色精度范围内的数,我们认为与0相等。
代码:
#include <iostream>
#include <cmath>
// 函数功能,返回a,b 是否相等
bool Comp_double(double a, double b)
{
// 定义一个误差常数,在误差范围内认为两数相等
const double ESP = 1e-14;
//return fabs(a - b) < (ESP);
return (a - b) >= -ESP && (a - b) <= ESP;
}
int main()
{
double i = 0;
while (!Comp_double(i, 1))
{
std::cout << i << std::endl;
//printf("%.17g \n", i);
i += 0.1;
}
return 0;
}
运行效果:
问题就处在这个double类型,Double 和 Float这两个类型都是有精度的,所以,循环十次之后, 这里的i 并不等于1, 而是约等于1.
具体等于多少,你可以多打印小数点后几位看看。