2

全て、

SAS が 2 つの 2 進変数の減算を処理する方法に関連する問題が発生しています。これらの結果は 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 からの変換) から数値精度の問題が発生している可能性があります。10 進表記で次のことを考えてください。

1 - (2/3) = 0.333

0.333 + (1/3) = 0.666

0.666 + (1/3) = 0.999

二項算術にも同様の問題がありますが、同一ではありません。ごくまれに、特定の種類の計算を行ったとき 1.0000000000000000000001423 に、1 ではなく 1 のような数値になってしまうことがあります。したがって、2 つの数値を比較したり、さらに計算を行ったりすると、期待した答えが得られない場合があります。

この問題を回避するには、いくつかのオプションがあり、いずれもなんらかの形式の丸めを使用することになります。計算の早い段階で数値を丸めることができます。これにより、精度が損なわれることはありませんが、この特定の問題を回避できる可能性があります。この目的のために特別に設計された FUZZ 関数またはその兄弟の 1 つを使用できます (数値が整数の 1E-12 内にある場合、最も近い整数を返します。ただし、10 進数値を扱っている場合は、これは使えません)。ROUNDZ (関数の fuzz ファミリの 1 つ) も役立つ場合があります。この例は、ROUNDZ のマニュアル ページから丸めたものですが、2 または 3 ではなく 2.50 または 2.51 に丸めるように変更されています。

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 のように、少し大きいものを選択する必要があるかもしれません。私は、整数の数学の場合にこれを解くことに慣れているだけです。

于 2013-01-18T17:13:48.583 に答える