2013-01-18 220 views
2

所有,SAS減去兩個值

當我跑步到與SAS是如何處理兩個兩位小數變量的減法一些問題得到錯誤的結果。這些結果寫入DB2數據庫。這裏所有使用的字段都導入到SAS和寫入DB2領域有小數(19,2)的數據類型下面是問題:

   AL_AMT  - PL_AMT  = DIF_AMT 
From SAS: 9,918,322.38 - 9,942,322.30 = (23,999.91) 
Expected: 9,918,322.38 - 9,942,322.30 = (23,999.92) 

下面是一些代碼非常修剪片段。毫無疑問,SAS很古怪。我希望有人能幫助我發現它的許多怪癖中的哪一個可能造成這種情況。

/* CAmt and PPmt are retrieved from a lengthy PROC SQL statement, */ 
/* their formats are unaltered.         */ 
data WORK.TABLE1; 
set WORK.TABLE0; 
Difference = CAmt - PPmt; 
run; 

data WORK.TABLE2(keep=Rep:); 
set WORK.TABLE1 end=last; 

If _N_=1 then do; 
    Rep1CAmt=0; 
    Rep1PPmt=0; 
    Rep1Diff=0; 

end; 

    Rep1CAmt+CAmt; 
    Rep1PPmt+PPmt; 
    Rep1Diff+Difference; 

if last; 

Rep1Diff=Rep1CAmt-Rep1PPmt; 
Rep1Diff=round(Rep1Diff,.01); 

/* I realize these two lines are redundant/unnecessary, but I was trying 
    different things to get the numbers to add up correctly, no such luck */  

run; 

data WORK.TABLE3; 
set work.TABLE2; 
AL_AMT=round(Rep1CAmt,.01); 
PL_AMT=round(Rep1PPmt,.01); 
DIF_AMT=AL_AMT-PL_AMT; 
run; 

proc append data=WORK.TABLE3 base=LIBNAME1.DB2TABLE(drop=ID) force; 
run; 

回答

3

當然,SAS沒有拿到直接減法錯誤:

data test; 
x=9918322.38; 
y=9942322.30; 
z=x-y; 
put _all_; 
run; 

賠率是你從早期的計算有一定數值精度的問題在這裏(或從DB2翻譯?)。想想十進制如下:

1 - (2/3) = 0.333

0.333 + (1/3) = 0.666

0.666 + (1/3) = 0.999

二進制算術有相似,但不完全相同的,問題。在極少數情況下,當做某些數學運算時,最後會得到一個數字,例如 1.0000000000000000000001423 而不是1.因此,當您比較兩個數字或進一步計算數字時,可能得不到您所期望的答案。

爲了避免這個問題,你有幾個選項,所有這些選項歸結爲使用某種形式的舍入。您可以在計算的某個早期點將數字舍入,不會影響您的準確性,但可能會避免此特定問題;您可以使用FUZZ函數或其中一個專門爲此目的而設計的函數(如果數字在整數的1E-12範圍內,它將返回最接近的整數) - 但如果您要處理十進制值,則可以無法使用此)。 ROUNDZ(絨毛家庭的功能之一)也可能是有益的 - 這個例子是從ROUNDZ手冊頁的鵝卵石,但修改爲圓形至2.50或2.51,而不是2或3

data test; 
format value round roundz BEST32.; 
    do i=12 to 19; 
     Value=2.505 - 10**(-i); 
     Roundz=roundz(value,0.01); 
     Round=round(value,0.01); 
     output; 
    end; 
    do i=18 to 12 by -1; 
     value=2.505 + 10**(-i); 
     roundz=roundz(value,0.01); 
     round=round(value,0.01); 
     output; 
    end; 
run; 

既然你使用浮點數,我建議四捨五入到1E-12範圍內的東西 - 所以, [number] = roundz([number],1E-12);

這通常會切斷模糊,並確保您的號碼始終如一地表現。你可能需要選擇稍大一點的東西,比如1E-10 - 我只是真的很熟悉解決這個整數數學問題,對於FP情況我認爲理論上是一樣的,但不完全有信心。

+0

謝謝喬,這解決了這個問題。 完全理解SAS可以在沒有問題的情況下進行簡單的減法,但在表格中,每次變換變量時我都要確保四捨五入到小數點後兩位。顯然這些步驟並沒有解決模糊問題。 –

+0

SAS支持固定精度類型嗎? 'DECIMAL'是一個固定的精度類型,並且使用浮點類型將數字存儲在_any_點處請求麻煩... –

+0

SAS不支持除NUMERIC和CHARACTER之外的任何類型。 NUMERIC是浮點數(類似於C中的DOUBLE)。 – Joe