2017年12月17日

【SAS小技巧】小心 “浮點運算陷阱”

先來看看下面這一個簡單的程式和結果。

data test;
     input x y;
     datalines;
     0.54 0.36
     54 36
;
data test1;
     set test;
     pct=((x-y)/y)*100;
     if pct=50 then chk=1;
run;
proc print data=test1;
run;

結果如下圖:

image

明明PCT看起來都是50,為什麼只有第2筆的CHK為1?

再來新增一小段程式:
data test2;
     set test1;
     format pct1 32.;
     pct1=pct*1000000000000000000;
run;
proc print data=test2;
run;

image

有沒有發現第1筆資料的PCT其實為50.000000000000016384。

其實這個問題是浮點運算的問題,電腦在運算小數點時候所產生的不精確性(這太專業我也沒辦法說清楚,留給GOOGLE大神解釋吧)。讀者可以閱讀SAS台灣官方網頁所建議的處理方法「SAS數值變數的儲存與運算」,下列文章也可以參考看看。

浮點數

Back to Basic: 談浮點數的比較

如何修正浮點算術中的進位誤差(EXCEL)EXCEL也會有同樣的問題

因此判斷式所用的變數內容「可能有小數」時,最好同時使用截斷函數(Truncation Function)於變數上,常用的截斷函數包括,ROUND(四捨五入)、INT(取整數)、CEIL(無條件捨去)、FLOOR(無條件進位)等,小數點截斷方法可以參考我寫的另一篇「小數點後做無條件捨去或進位」。

重新把判斷式新增截斷函數後,即可得到正確的結果了。

data test3;
     set test;
     pct=((x-y)/y)*100;
     if round(pct,1)=50 then chk=1;
run;
proc print data=test3;
run;

image

這個問題我已經知道很久了~但也沒想到要寫出來,主要是因為沒有人問過我啊。所以很感佩黃小學妹的細心,她希望這樣經驗應該分享給更多人知道,哪就寫吧,而且最近不小心拿得到一個機械鍵盤,突然愛上打字了~~~希望這次內容對各位有所幫助。

沒有留言:

張貼留言