浮點數陷阱

來源:互聯網
上載者:User

看下面一段程式

#include <stdio.h>int main(){double i;for(i = 0; i != 10; i += 0.1)    printf("%.1lf\n", i);}

你也許覺得這個程式很容易理解;但是請別相信自己的想象力,運行一下:

什麼無限輸出下去??

不是按到底到10的時候會停止嗎?

再看一段程式:

#include <cstdio>#define exp 0.000001int main(){if(0.1+0.1+0.1 == 0.3)      printf("equal\n");  else      printf("not equal\n"); return 0;}

你覺得應該輸出的是:equal 

但是運行下:什嗎? not equal???

好吧,我們來討論下;

首先,我們來明白一個概念:

實際上,電腦中的所有資料都用二進位表示,包括浮點數。這就導致某些浮點數不能用二進位精確表示,例如0.1(這很容易理解,就像10/3不能被十進位精確表示一樣)

進一步地說,浮點數是採用分數+指數來表示的,例如

0.5 = 1/2

0.75 = 1/2 + 1/(2^2)

0.875 = 1/2 + 1/(2^2) + 1/(2^3)

0.1 = 1/(2^4) + 1/(2^5) + 1/(2^8) + ...

其中0.1隻能無限迴圈下去,這就意味著0.1在電腦中不能被精確表示,因此產生上述兩個陷阱也就很容易理解;

那麼,我們來怎麼處理這個問題? 首先我們一定不能用 ==   

然後;

拿第一個例子為例,你是不是會想到fabs(A-B) < epsilon 這樣的一種判別方法 ;

這個方法在一定情況下是可行的;

但是有一種情況卻會出問題;比如,你的 epsilon 取值為 0.00001  那麼我比較的資料是0.00005和0.00006也會判斷為相等;

這個epsilon實際上是我們常說的絕對誤差;

為了避免這個絕對誤差,我們會想到用相對誤差;

而更精確的結果判斷相等,參見下列函數:

bool IsEqual(float a, float b, float absError, float relError ) {   if(a==b) return true; if(fabs(a-b)<absError ) return true; if(fabs(a>b)) return fabs((a-b)/a>relError) ? true : false; if(fabs(a<b))return fabs((a-b)/b>relError) ? true : false; }  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.