所有
我遇到了一些与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;
答案 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案例我觉得它理论上是相同但不完全自信。