2

全部,

我遇到了一些与 SAS 如何处理两个两位小数变量的减法相关的问题。这些结果被写入 DB2 数据库。此处使用的所有字段都导入到 SAS 并写入数据类型为 DECIMAL(19,2) 的 DB2 字段这是问题所在:

             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;
4

1 回答 1

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(fuzz 系列函数之一)也可能有帮助 - 这个例子是从 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);

That will generally cut off the fuzziness and make sure your numbers consistently behave. You might need to pick something slightly larger, like 1E-10 - I'm only really familiar with solving this for integer math cases, for FP cases I think it's theoretically the same but not entirely confident.

于 2013-01-18T17:13:48.583 回答