在程序中如何判斷兩個浮點數相等


                                                       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.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM