数値を四捨五入して文字変数に格納したい場合、PUT関数を使ってませんか?
以下の例を見てみましょう。
想定通りの結果
data DT1;
length B $10.; A = 1.25; B = left(put(A, 12.1)); put B=; run; B=1.3 |
小数第2位を四捨五入して文字化した変数が出来ました。
想定外の結果
data DT1;
length B $10.; A = 4.1-4.05; B = left(put(A, 12.1)); put B=; run; ログ B=0.0 |
これは浮動小数点誤差ってやつのせいですね。
http://sas-tumesas.blogspot.jp/2014/03/blog-post_14.html (データステップ)100万回)つまり「4.1-4.05」は「0.05」ではなく「0.049999999・・・」みたいな値で格納されてます。
だからPUT関数で「0.0」という値が帰ってきたわけですね。
で、これをどうするかは各自(各社)いろいろ考え・やり方があると思います。
よくROUND関数をかませたりしますが、、、
data DT1;
length B $10.; A = 4.1-4.05; B = left(put( round(A,0.1) ,8.1)); put B=; run; ログ B=0.1 |
📝ROUND関数には注意すべき動きがある
ROUND関数は「第1引数を第2引数の最も近い倍数に丸める関数」ですが、
その独特の動きや制限も重要です。以下にSAS社のドキュメントの記述を抜粋します
(※日本語ドキュメントは誤記がある?のでちょっと分かりにくいですが英語の方を示します。。)
The Effects of Rounding |
「第1引数を第2引数の最も近い倍数に丸める」処理において、10進数の算術と2進数の算術では「正確な倍数」の扱いの違いがあって、そこをROUND関数では調整してるような事が書かれているのでしょうか(間違っていたらご指摘をお願いします)
Producing Expected Results |
期待される結果を生成する条件が示されています。思ったより扱える範囲が狭い?
ちなみに文中の、significant digits と decimal places の意味を混同してるケースをよく見かけるので注意。
その他の挙動についてもドキュメントに書かれているので、要確認!
ROUND関数を単純に四捨五入するやつと思っていると、想定外の結果になるかもしれません。
例えば以下のように最後の桁が「8」か「9」かで結果が異なっています。
data DT1;
A = round(1.049999999998,0.1); B = round(1.049999999999,0.1); put A= B=; run; ログ A=1 B=1.1 |
というわけで、一概にこうすればいいってのはない気がします。
「私はこうしてます」 とか何かアイディアがあったら教えてほしいです。
0 件のコメント:
コメントを投稿