大家应该都知道浮点数存在精度问题,所以问题就来了,我如何才能判断两个数是否近似相等,或者某个浮点数是否为0。
其实这是一个问题,对于前者,我们需要二者作差,然后与0进行比较。这样前者与后者就是同一个问题了,即如何判断某个浮点数是否为0。我所知道的比较简单但是不是很好的方法就是使用1e-7或者更小的数,如下所示(以单精度为例):
#include <iostream>
#include <cfloat>
using namespace std;
int main()
{
float num;
cout << "输入一个数:";
cin >> num;
if (num < 1e-7 && num > -1e-7)
cout << num << "近似为0" << endl;
else
cout << num << "不近似为0" << endl;
return 0;
}
上述方式以C++代码为例。由于不同编程语言有不同的处理方式,大家可以不限制使用任何编程语言。当然,如果您有更通用的方式当然再好不过了。
多小才是“足够小”,应该是由处理的具体问题决定的。比如用
double
表示金额的话,1e-4
就可以认为是零了。而如果进行科学计算,恐怕1e-7
还嫌太大。<cfloat>
中有定义DBL_EPSILON
为与1.0
最接近的差值。参见这里。浮点数的比较还是要根据实际存储规则来,因为浮点数是以二进制来存储的,而用二进制表示十进制是不能精确表示的,即使浮点数的十进制有效数字比较少,那也不一定能用二进制精确表示。为什么呢?
首先浮点数小数位的二进制是这样对应的:
小数后1位:0.5 (2^-1)
小数后2位:0.25 (2^-2)
...
小数位n位:2^-n
也就是说,任何一个浮点数的小数部分都是由2^-1 ... 2^-n组合而成的,这样就能理解为什么有效位数少的浮点数也不能精确表示了,比如0.3,就无法用上面的位数组合而精确表示出来,不信cout试试:
输出:0.30000001192092896
而如果把0.3换成0.5,那就可以了,因为0.5可以用2^-1精确表示啊!同理,0.625也可以。
那我们平时为什么cout << 0.3;可以直接输出0.3呢?那是因为cout默认做了舍入处理。
回到楼主的问题:如果是直接判断0.3 == 0.3,那没问题,因为同样的数字做了同样的表示,所以可以直接用'=='。如果是可以精确表示的数,比如0,则更是如此了。
但是如果判断0.1+0.2和0.3是否相等,那就不行了,因为他们都有精度损失,而损失的数值又不一样,所以不能直接比较需要用
abs((0.1+0.2) - 0.3)<EPSILON
这样的方法。计算机表示浮点数(float或double类型)都有一个精度限制,对于超出了精度限制的浮点数,计算机会把它们的精度之外的小数部分截断。因此,本来不相等的两个浮点数在计算机中可能就变成相等的了。例如: