2013-01-18 171 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