「小数点以下の桁数を指定して切り捨てを行なう方法」が上手く行かなかった話 - SAS
「小数点以下の桁数を指定して切り捨てを行なう方法」がSAS社のQAにあったので試したところ、上手く行かなかった。 大旨、うまくいくのだけれど、一部の値がおかしな結果になるみたい。
サンプルプログラム1
data test ; input a ; cards ; 10 10.1 10.12 10.25 10000 123.123 9.9 9.99999 -100 -10.1 -1.12 -1.000 260.9 260.4 run ; data _null_ ; set test ; b = a * 100 ; c = int(b) ; d = c / 100 ; putlog a= b= c= d= ; run ;
実行ログ1
a=10 b=1000 c=1000 d=10 a=10.1 b=1010 c=1010 d=10.1 a=10.12 b=1012 c=1012 d=10.12 a=10.25 b=1025 c=1025 d=10.25 a=10000 b=1000000 c=1000000 d=10000 a=123.123 b=12312.3 c=12312 d=123.12 a=9.9 b=990 c=990 d=9.9 a=9.99999 b=999.999 c=999 d=9.99 a=-100 b=-10000 c=-10000 d=-100 a=-10.1 b=-1010 c=-1010 d=-10.1 a=-1.12 b=-112 c=-112 d=-1.12 a=-1 b=-100 c=-100 d=-1 a=260.9 b=26090 c=26089 d=260.89 a=260.4 b=26040 c=26039 d=260.39
見事に誤差がでてますね。ちなみに、int を floor に変更しても同じ結果。 切り捨てるどころか、むしろ小数桁を増やしてます(´・ω・`) どうも100倍した時点で、期待通りの値になっていないぽいです。
サンプルプログラム2
data _null_ ; a = 260.4 ; b = a * 100 ; c = 26040 ; putlog b= c= ; if a = b then putlog "同じだよ!" ; else putlog "別者だよ!" ; bx = put(b, hex16.) ; cx = put(c, hex16.) ; putlog bx= cx= ; run ;
実行ログ2
b=26040 c=26040 別者だよ! bx=40D96DFFFFFFFFFF cx=40D96E0000000000
見た目、同じ値なのですが、内部的な値は別者です。 なので、int したときに、違う値になってしまったのですね。 対策としては、「背筋が凍る、厄介でおっかない小数点誤差の話」で紹介されてるように、適当な値で丸める方法くらいしかないぽい?
サンプルプログラム3
data test ; input a ; cards ; 260.9 260.4 run ; data _null_ ; set test ; b = a * 100 ; b = round(b, 0.00001) ; c = int(b) ; d = c / 100 ; putlog a= b= c= d= ; run ;
実行ログ3
a=260.9 b=26090 c=26090 d=260.9 a=260.4 b=26040 c=26040 d=260.4
これでうまくいきそうですけど、もっとスマートな方法はないものですかね・・・。
コメント
コメントを投稿