有沒有使用「==」判斷浮點數相等與否出現錯誤的例子?

有沒有使用「==」判斷浮點數相等與否出現錯誤的例子?

也就是,什麼情況下「==」會失效?


一般來講,==和!=在針對浮點數的時候,兩邊都必須是字面量。意思就是,左邊是1.0,右邊是1.0,他們中間複製了幾次,總之只要他們不是被計算出來的,可以比較。

但是如果是計算出來的——可沒有人告訴你0.1+0.1就是0.2。0.1這個值其實是不存在的,因為它不能被處理成一個2進位的有限小數。所以你對兩個不存在的值進行相加,就會得到一些奇怪的誤差,所以才不能==。

到底0.1+0.1和0.2相比,到底是誰大誰小還是一樣,完全取決於你的C++編譯器在對付2進位無限小數的時候,到底用什麼樣的截斷策略——譬如說ceil、floor、round,都是有可能的。如果這個策略你已經清楚了,那你自己也可以判斷到底是什麼結果。

反過來,只要是精度以內的二進位有限數字就可以。譬如說,0.25+0.25,肯定就==0.5,沒有問題。


15.1 * 100 + 0.9 * 100 == 16.0 * 100 返回值為true

16.1 * 100 + 0.9 * 100 == 17.0 * 100 返回值為false

(16.1 + 0.9) * 100 == 17.0 * 100 返回值為true

16.1 + 0.9 == 17.0 返回值為true

就問你怕了沒


這個問題之前在《高質量c++編程指南》中看到過,現引用原文:

【規則4-3-3】不可將浮點變數用「==」或「!=」與任何數字比較。

千萬要留意,無論是float 還是double 類型的變數,都有精度限制。所以一定要避

免將浮點變數用「==」或「!=」與數字比較,應該設法轉化成「&>=」或「&<=」形式。

假設浮點變數的名字為x,應當將

if (x == 0.0) // 隱含錯誤的比較

轉化為

if ((x&>=-EPSINON) (x&<=EPSINON))

其中EPSINON 是允許的誤差(即精度)。

應該可以回答你的問題


以前看過一篇博文,解釋的比較清楚,原文找不到了,大意就是float佔4位元組,01排列組合最多4294967296種可能(40多億),但float的取值範圍是-2^128 ~ +2^128遠遠多於理論值,因此其中絕大多數都是不精確的

舉例來說,0.1~0.9這9個數中只有0.5能用二進位精確表示,其它全是不精確的近似值,因此積累一定量後肯定有較大誤差的,比如

#include&
int main()
{
float f=0.0f;
for(int i=0;i&<10;++i) { f+=0.1; } if(f==1.0) { std::cout&<&<"all right"&<&

最後輸出what the fuck,調試可得f=0.9999999999999

更新:

憑著對"只有0.5能用二進位精確表示"這句頗具震撼力的話的精確記憶,我還是找到了原文——代碼之謎(五)


兩種數的獲取方式不一樣。比如一個是字面量另一個是計算量。這樣就可能不相等

但是也有例外。比如符合c++中的is_iec559規範也能確保相等

x == sqrt(x*x)


例子:

double a = 3456789.0,
b = 0.3456789;
while (a &> 1)
a/=10.0;

理論:IEEE 754-1985 是基數為2的浮點數表示,和十進位的互相轉化有很大幾率出現截斷誤差。

==是判斷二進位位,幾乎任何時候都會出現錯誤。

IEEE floating point 或 IEEE 854 浮點數的基數為10時,可以避免這個問題。

PS: 代碼插入真是難用得一塌糊塗!


有啊。

記得是某次暑期多校賽還是網路賽還是隊內訓練賽來著。使用fabs(x-y)&<=1e-8,結果錯了了。後來改為x==y就過了。


簡單來說,當二進位不能精確表示的數進行運算時就可能會出現浮點誤差。


float a = 0.1;

float b = 0.2;

float c = 0.3;

if (a + b == c)

cout &<&< "==" &<&< endl;

else

cout &<&< "!=" &<&< endl;


我這邊就舉一個關於浮點數進度的小栗子給大家看看。在我們經常設置機器參數的過程中,有時候需要設置機器的浮點數參數,比如說角度參數(有些編碼器的精度非常的高)。如果你在上位機中設置的邏輯是:如果讀取的機器參數不等於我設置的參數,那就就發送數據去修改機器的參數,直到二者相等。如果你是這樣的邏輯,那恭喜你,上位機和機器成功的掛了。因為數據在傳輸和捨棄的時候精度一般會損失,一般情況下二者是不會相等的。

我想說的是什麼,我在工程中遇到的問題給我的結論是:沒有絕對的等於,只有誤差允許內的相等。在做上位機的時候也會依然考慮到這個情況,編譯器內部也是沒有絕對的等於。只是恰好在它誤差允許範圍內而已。所以浮點數用等於,你就可以考慮一下時候可以用大於,小於來替代,我覺得會更嚴謹。


數值分析果然是程序員必修課


樓主去做兩道計算幾何的題就知道了....

x y是否相等一般是判斷abs(x-y)&<=1e-8 這個1e-8是自己設立的任意精度....


浮點數沒有這樣判斷的~應該是相減小於一個很小的數


前面那麼多人解釋了,我來解釋下根本原因吧。

大部分電腦的浮點數表示使用的是IEEE754浮點數標準。

比如1.2500012是3fa0000a

1.2500013也是

1.2500014是3fa0000b

1.2500015是3fa0000c

你會發現1.2500012f等於1.2500013f,但是14和15不想等


這並不需要數值分析啊,祭祖就能告訴你不能亂==了吧


。。。這不是經常發生的嗎?典型情況是在大量計算而結果趨近於0的時候的,一個絕對值很小的數和0.0使用==得到的是false。所以在競賽的時候我們一般會根據題目要求的精讀設定一個閾值,例如

const double eps =1e-7;

bool isEqual(double a, double b){

return fabs(a - b) < eps;

}


0.1 + 0.2==0.3

js 內 false


#include&
#include&
int main(){
float x = 1.0f;

float y = 1.0f / 10;
printf("%.10f %.10f
",x,10.0*y);
if (10.0 * y == x){
printf("10.0*y == x
");
}
return 0;
}

如果以基數為2表示浮點數,則對於小數0.1,不能精確表示。


先說結論,沒有。

舉個例子,你把int叫做「整數」,是不是說int就是你上數學課的整數了?當然不是,int就是int,是c代碼里的一個抽象的東西。「整數」可以超級大,int是有範圍的。只不過是當數據不大時int和整數在數學上的表現極為相近而已。

同理,float就是float,float不是浮點數。==也只能判斷float是不是相等,不能判斷浮點數是不是相等。無論==的內部實現和你的數學常識有多大差異,只要==認為float相等,他們就一定是相等,否則就一定不等。問題出在你平時用的浮點數相等實際是在大腦里作了一個強制轉換,把浮點數轉換成了float,這個強制轉換是不一定正確也不一定可逆的。


使用兩個數差絕對值小於一個小量來進行浮點數是否相等的判斷,這大概是唯一的方法。


推薦閱讀:

怎樣開發一款有限元軟體,從哪些方面學習?
C++ #include " " 與 <>有什麼區別?
C++ 函數返回局部變數的std::move()問題?
在開發大C++工程的時候如何判斷和避免循環include?
為什麼C++使用sizeof關鍵字的時候不需要include <cstddef>頭文件就可以使用?

TAG:編程語言 | C編程語言 | C | CC |