SAS在减去两个值时得到错误的结果

时间:2013-01-18 16:21:38

标签: db2 sas

所有

我遇到了一些与SAS如何处理两个二进制变量减法相关的问题。这些结果将写入DB2数据库。此处使用的所有字段都导入到SAS并写入DB2字段,数据类型为DECIMAL(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;

1 个答案:

答案 0 :(得分: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案例我觉得它理论上是相同但不完全自信。