マクロ
自作マクロ故に担保はしない。
使う前に適当にテストしてほしい。
なお、指摘受け付ける。
著作権については、好きにしていいよ。
使い方
%mround_digit :
[出力先の文字変数]=%mround_digit([元データになる数値変数], [有効桁数]) ;[有効桁数]は1以上の整数。
マクロ中身
%macro mround_digit(var, digit) ; ifc( &var.=0 ,ifc(&digit=1,"0","0." || strip(repeat("0",&digit.-2))), strip(putn( round( &var. ,10 ** ifn( int(log10(abs( &var.)))>=0 ,int(log10(abs( &var.)))-&digit.+1 ,int(log10(abs( &var.)))-&digit. ) ) ,'12.' || strip(putn( ifn( ifn( int(log10(abs( &var.)))>=0 ,int(log10(abs( &var.)))-&digit.+1 ,int(log10(abs( &var.)))-&digit. ) >0 ,0 ,- ifn( int(log10(abs( &var.)))>=0 ,int(log10(abs( &var.)))-&digit.+1 ,int(log10(abs( &var.)))-&digit. ) ) ,'12.0' )) )) ) %mend mround_digit ;
例
data TEST ; input a best12. ; cards ; 1.10122 112.222 3332001 -1.10122 -112.222 -3332001 0.002455 0 1 10 1515151 115.151 ; run ; data RESULT ; set TEST ; attrib b c d e f length=$200. ; b=%mround_digit(a,1) ; c=%mround_digit(a,2) ; d=%mround_digit(a,3) ; e=%mround_digit(a,4) ; f=%mround_digit(a,8) ; run ; proc print data=RESULT ; format a best12. ; quit ;
結果
SAS システム 2020年 9月29日 火曜日 16時05分24秒 5 Obs a b c d e f 1 1.10122 1 1.1 1.10 1.101 1.1012200 2 112.222 100 110 112 112.2 112.22200 3 3332001 3000000 3300000 3330000 3332000 3332001.0 4 -1.10122 -1 -1.1 -1.10 -1.101 -1.1012200 5 -112.222 -100 -110 -112 -112.2 -112.22200 6 -3332001 -3000000 -3300000 -3330000 -3332000 -3332001.0 7 0.002455 0.002 0.0025 0.00246 0.002455 0.0024550000 8 0 0 0.0 0.00 0.000 0.0000000 9 1 1 1.0 1.00 1.000 1.0000000 10 10 10 10 10.0 10.00 10.000000 11 1515151 2000000 1500000 1520000 1515000 1515151.0 12 115.151 100 120 115 115.2 115.15100
FCMPで関数自作
普通のプログラム言語のように関数が作れるのだが、便利と言えば便利だが、デバッグライトが分からんのでどう作るかが悩みの一つ。
もうひとつは、あまりにもあっさり自作出来るのだが、標準関数とパッと見分けつかないので困るなというところか。
なお、関数を使うのに、システムオプションでCMPLIBを設定する必要がある。
作り方
proc fcmp outlib=work.funcs.math ; function round_digit(var, digit) $ varchar(32767) ; attrib str length=varchar(32767) ; str=" " ; if var=0 then do ; if digit=1 then do ; str="0" ; end ; else do ; str="0." || strip(repeat("0",digit-2)) ; end ; end ; else do ; attrib mult rd rd2 var2 length=8 ; attrib fmt length=varchar(32767) ; mult=int(log10(abs( var))) ; if mult >= 0 then do ; rd = mult - digit + 1 ; end ; else do ; rd = mult - digit ; end ; if rd > 0 then rd2 = 0 ; else rd2 = - rd ; var2 = round(var,10**rd) ; fmt = '12.' || strip(put(rd2,12.0)) ; str = strip(putn(var2,fmt)) ; end ; return(str); endsub; quit ;
例
options cmplib=work.funcs; data TEST ; input a best12. ; cards ; 1.10122 112.222 3332001 -1.10122 -112.222 -3332001 0.002455 0 1 10 1515151 115.151 ; run ; data RESULT ; set TEST ; attrib b c d e f length=$200. ; b=round_digit(a,1) ; c=round_digit(a,2) ; d=round_digit(a,3) ; e=round_digit(a,4) ; f=round_digit(a,8) ; run ; proc print data=RESULT ; format a best12. ; quit ;
結果
SAS システム 2020年 9月29日 火曜日 19時14分00秒 25 Obs a b c d e f 1 1.10122 1 1.1 1.10 1.101 1.1012200 2 112.222 100 110 112 112.2 112.22200 3 3332001 3000000 3300000 3330000 3332000 3332001.0 4 -1.10122 -1 -1.1 -1.10 -1.101 -1.1012200 5 -112.222 -100 -110 -112 -112.2 -112.22200 6 -3332001 -3000000 -3300000 -3330000 -3332000 -3332001.0 7 0.002455 0.002 0.0025 0.00246 0.002455 0.0024550000 8 0 0 0.0 0.00 0.000 0.0000000 9 1 1 1.0 1.00 1.000 1.0000000 10 10 10 10 10.0 10.00 10.000000 11 1515151 2000000 1500000 1520000 1515000 1515151.0 12 115.151 100 120 115 115.2 115.15100
悩ましいなあ
先に書いたが、FCMP関数で作ってしまうと、普通の関数みたいに見えすぎるのがアレ。
そして、FCMPプロシージャの使い方をまだ探り探りやってる(ヘルプにもあんまり載ってない)ところもあって、自信がない。
文字変数の定義これでいいのかも分からん(パッと見文法見つけられてない)。
マクロの方が何やってるかはまだ分かりやすいかもなあ。
ただ、この手の文法は、今後のSASを考えると増えていくとは思う。ただ、マルチスレッドプログラミングとかやる機会は治験ではなさそうだし、世間的にもそういうのを意識してコーディングしていくというのも需要ないだろうし。うーん。
追記
log10を使わずにE表記使っての対応が可能なのに気づいたが、今更なのでいいや。やってることはlog10と変わらないし。