数値を丸める関数 round, rounde, roundz の違い - SAS

round 関数
四捨五入ぽい計算をしてくれる関数です。
第1引数がだいたい中間の値(近似値)の場合は、絶対値が大きい方に丸めます。
rounde 関数
偶数丸め(銀行丸め / JIS丸め)ぽい計算をしてくれる関数です。
第1引数がだいたい中間の値(近似値)の場合は、偶数の方に丸めます。
roundz 関数
偶数丸め(銀行丸め / JIS丸め)計算をしてくれる関数です。
round 関数や rounde 関数と違い、ちょうど中間の値で丸めてくれます。ただし、第2引数が1以下であったり、整数の逆数(例. 整数3 の逆数 1/3)でない場合だと、実際の計算と違う値になることがあります。

偶数丸めとはなにかというと、丸めをする桁数の1つ上の桁数が偶数の値に丸める処理のことです。

例えば、小数第1位を四捨五入する場合、0.5 は 1 になりますが、偶数丸めでは 0 になります。0.5 は、1 と 0 のちょうど中間で、偶数は 0 の方なので、偶数丸めでは 0 に丸められます。では、1.5 を小数第1位で四捨五入すると 2 になり、偶数丸めでも 2 になります。

※ ゼロは奇数ではなく、偶数です

値によって丸められ方が変わる偶数丸めですが、何がメリットがあるかというと、丸めた値の合計などを求めるときにあります。値を丸めてしまうと実際の値とは異なった値になってしまうため、誤差が生じてしまいます。このとき、四捨五入よりも偶数丸めの方が誤差が少ないというメリットがあります。

ところで、言語によって round 関数で実装されている丸め方は違います。エクセルでは四捨五入ですが、VBAだと偶数丸めです。round 関数を使用する場合、使用している言語の仕様を調べておくとトラブルを回避できるかと思います。


さてさて、実際に SAS でのそれぞれの関数の違いを見てましょう。

(コード内に使用している proc report の指定行を強調する方法については、proc report 指定行(◯行目)を強調する - SAS をご参考ください。)

/* ORG で指定した数に対して、10回 数値ADDを加算していき、               */
/* 加算していくたびに、ROUNDで指定した桁で丸め処理を実施する            */ 
/* 丸め処理は、関数round, rounde, rounzで行い、それぞれの結果を比較する */
/* 結果は、proc report によって出力され、4~6行目は強調表示される       */
/* -------------------------------------------------------------------- */
/*   ORG   : 最初の数                                                   */
/*   ADD   : 加算する数値                                               */
/*   ROUND : 丸める桁数                                                 */
/*   FORM  : リスト出力時の数値format                                   */
%macro TEST_ROUND(ORG, ADD, ROUND, FORM) ;
  /* データ作成 */
  data TEST ;
    drop I ;
    NUM = &ORG. ;
    do I = 1 to 10 ;
      NUM + &ADD. ;
      NUM_ROUND  = round(NUM, &ROUND.) ;
      NUM_ROUNDE = rounde(NUM, &ROUND.) ;
      NUM_ROUNDZ = roundz(NUM, &ROUND.) ;
      output ;
    end ;
  run ;

  /* データを強調してリスト表示 */
  proc report data=TEST nowd ;
    column NUM NUM_ROUND NUM_ROUNDE NUM_ROUNDZ ;
    define NUM / display style=[TextAlign=Center BackgroundColor=AliceBlue FontStyle=Italic] format=&FORM. ;
    define NUM_ROUND  / display style=[TextAlign=Center] format=&FORM. ;
    define NUM_ROUNDE / display style=[TextAlign=Center] format=&FORM. ;
    define NUM_ROUNDZ / display style=[TextAlign=Center] format=&FORM. ;
    
    compute NUM ;
      COUNT + 1 ;
      /* 4, 5, 6行目だけにスタイルを適用 */
      if COUNT in (4, 5, 6) then do ;
        call define(_ROW_, 'style', 'style=[Color=Crimson BackgroundColor=yellow BorderColor=RoyalBlue BorderWidth=6]') ;
      end ;
    endcomp ;
  run ;
%mend TEST_ROUND ;

title "小数あり(正の値) - 偶数" ;
%TEST_ROUND(4.40, 0.01, 0.1, 6.2) ;
title "小数あり(正の値) - 奇数" ;
%TEST_ROUND(4.50, 0.01, 0.1, 6.2) ;

title "小数あり(負の値) - 偶数" ;
%TEST_ROUND(-4.40, 0.01, 0.1, 6.2) ;
title "小数あり(負の値) - 奇数" ;
%TEST_ROUND(-4.50, 0.01, 0.1, 6.2) ;

title "整数 - 偶数" ;
%TEST_ROUND(100, 1, 10, 4.) ;
title "整数 - 奇数" ;
%TEST_ROUND(110, 1, 10, 4.) ;

title "スゴイ小さい数" ;
%TEST_ROUND(1.499999999995, 1E-12, 1, 15.13) ; /* 1E-12 : 0.000000000001 */


小数第1位は 4 なので、4.45 では rounde, roundz は 4.4 に丸められます。


4.55 では全て 4.6 に丸められる・・・と思いきや、roundz では 4.5 になっています。最初の関数の説明に書きましたが、roundz は小数桁を丸めるとき、うまく丸めてくれないことがあります。


負の数では round関数の四捨五入は、絶対値が大きい方に丸められることに注意してください。


またまた、-4.55 のところで、roundz がうまく偶数丸めしてくれていないです。


整数でも丸められます


最初の関数の説明で、だいたい中間の値とか、ちょうど中間の値とか曖昧なこと書きました。round 関数や rounde 関数は、実際の値に近しい値に変換するファジー処理というのを行なっているようです。なので、凄く小さい数を扱うときは実際の結果と異なる場合があります。roundz 関数は、このファジー処理を行わずに処理が実施されます。



参考サイト

  1. 端数処理 | Wikipedia
  2. ROUND関数は四捨五入でなく偶数丸め(銀行丸め)になる場合があることを知らないと大変なことになるかもよ? | ラブグアバ
  3. [C]整数に丸める時の注意 | DiaryException
  4. ゼロの偶奇性 | Wikipedia
  5. 0(ゼロ)は奇数?偶数? | 理科担当のシコウ - Z会ブログ

コメント

このブログの人気の投稿

日付フォーマットでない文字項目をSAS日付に変換するときにログ出力されるメッセージを抑制したい - SAS

データセット(.sas7bdatファイル)の文字コードを取得したい - SAS

Linuxコマンド: date で◯か月前 / ◯か月後を取得するときの注意