ACM於1990年宣佈William M. Kahan在浮點數運算標準的制定上的貢獻而得到圖靈獎[1]。
--關於浮點數
極理想狀況下,判斷兩個實數 a 和 b 相等,這裏不妨將兩個數分別定義爲double型,直接使用 a == b 語句。衆所周知,這樣的代碼是不能正常工做的,緣由是,1.0000001 和 1.0 這兩個數在絕大多數的狀況下,認爲它們是相等的,因此常常能看到以下的 C 或者 C++ 代碼 if(fabs(a-b)<=eps_0) ,通常地,eps_0設置爲很小的數,好比1.0e-6 或者 1.0e-7,直觀地來說,就是說當兩個數之間的距離(稱爲絕對偏差)很小很小的時候,咱們就認爲它們是相等的。
若是數字的數量級很大時,好比下面這兩個數10000.0001和10000.000,顯然使用上述的距離判斷的結果二者不相等,不過,咱們來看它們之間的相對偏差爲(1000.0001-10000.000) /10000.000=1.0e-9,那麼這二者也應該認爲是相等的,因而使用相對偏差的想法,將代碼改寫爲 if(fabs(a-b)<=eps*fabs(a)) [2] 。 相對和絕對的區別,就像前段時間朋友圈普遍流傳的關於賺錢這件事情,別人的一個小目標是別人的小目標,每一個人要根據本身的能力有本身的小目標(相對),若是把別人的小目標看成全部人的小目標(絕對),只是一句調侃而已,天然當不得真。
使用相對偏差能夠迴避掉數字數量級較大的問題,不過,它對於數量級較小的問題解決起來效果不佳,考慮一種極端狀況,好比被比較的兩個數字分別爲 a=0.0 和 b=0.00000001,這個時候這兩個數字相差很小,認爲相等,可是使用相對偏差的代碼時,因爲右端項爲零,而左端項大於零,顯然等式不成立,即便用該方法判斷兩個數字並不相等。 比較完善的方式是將絕對偏差和相對偏差結合起來考慮,來設計C++代碼:
bool isEqual(const double a, const double b) {
const eps_0 = 1.0e-6, rel_error = 10e-4;
bool isEqualFlag = FALSE;
if (fabs(a-b)<=eps_0) {
isEqualFlag = TRUE;
}
else {
if(fabs(a) >= 1000.0) {
if(fabs(a-b)<=rel_error*fabs(a)) {
isEqualFlag = TRUE;
}
}
}
return isEqualFlag;
}
這段函數貌似應該能夠正常工做了,程序中的 rel_error 和 1000.0 能夠根據實際須要進行修改,紅色的標註部分是採用王珉老師的關於分狀況討論的方式,這樣相較於不分狀況討論的方式來講,可以有效減小計算量,有興趣的同窗童鞋能夠查看後面的回覆。
注:讀過 Kanan 的文章或者書,名字有印象,讀的內容則徹底木有印象了 :-(
參考資料:
[1] http://baike.baidu.com/link?url=dKEdlcVXDrqZPOwlYrdGJHIUj2R2o6FTrytdnEKegTdp8pAobEAgln8xafbg9aVeGrmX7ZZDzfH4EmpnmOLCYzDnlvuhooaZwN1Hr1V53gkTmvLeTCuHbZrd4DAOaYoMHoWy35OqHJ_iW42A1fT61q
[2] http://baike.baidu.com/link?url=zliuoxROiLTdcJ7gdz0smcHam_4wEUeOpbFJG_mvS7aicaZvHt37-w0GYSi83ApuCAAGi-O8-7NrStNdPMciN4ztQFvyYBlHrjVv8YIgZmEoK2gllb-3cjV9j9cSEC7E
[3] http://www.cnblogs.com/zourrou/archive/2011/05/08/2040712.htmlhtml