大家应该都知道浮点数存在精度问题,所以问题就来了,我如何才能判断两个数是否近似相等,或者某个浮点数是否为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 cout預設做了舍入處理。
回到樓主的問題:如果是直接判斷0.3 == 0.3,那沒問題,因為同樣的數字做了同樣的表示,所以可以直接用'=='。如果是可以精確表示的數,例如0,則更是如此了。
但是如果判斷0.1+0.2和0.3是否相等,那就不行了,因為他們都有精度損失,而損失的數值又不一樣,所以不能直接比較需要用
abs((0.1+0.2) - 0.3)<EPSILON
這樣的方法。計算機表示浮點數(float或double類型)都有一個精度限制,對於超出了精度限制的浮點數,計算機會把它們的精度之外的小數部分截斷。因此,本來不相等的兩個浮點數在計算機中可能就變成相等的了。例如: