COLOR(red){SIZE(25){JIS, ISO 式四捨五入}}

[[なんでも掲示板]] の中間さんの投稿記事参照。

桁数の多いデータはしばしば丸め処理 (rounding) される.よく知られたものに,
切り下げ,切り上げ,そして四捨五入がある.四捨五入は切り上げ,切り下げが
相半ばし,長い目で見ると公平であるといわれるが,実際は,少しだけ大きめに
丸める傾向があることは,次の表から分かる.

|元の数        | 3.0 | 3.1 |3.2 |3.3 | 3.4  |3.5 | 3.6 | 3.7 | 3.8 | 3.9 |
|四捨五入後 | 3   | 3   | 3    |3    |3     |4    | 4    |4     | 4   | 4     |
|差                | 0.0 | -0.1 | -0.2 | -0.3 | -0.4 | 0.5 | 0.4 | 0.3 | 0.2 | 0.1|

JIS(日本工業規格)や,ISO(国際標準化機構)では,任意の桁位置における丸め処理法を次のように定めている(JIS Z 8401方式およびISO 3110 方式).
この方式は10進法だけでなく,2進法等にも適用される.R の四捨五入関数 
COLOR(red){round} は IEEE 754 方式 (IEEE 規格は計算機における数値処理の基本を定める)に
基づき、
これは JIS, ISO 方式と一致 (簡単にいえば誤差が最小になるように丸めるということ)
するが、小学校で習った四捨五入とは微妙に食い違う(COLOR(magenta){つまり五入ばかりでなく五捨もあり得るの})ので注意が必要である。
するが、小学校で習った四捨五入とは微妙に食い違う(COLOR(magenta){つまり五入ばかりでなく五捨もあり得る})ので注意が必要である。

- (1) 一番近い丸め結果候補が1つだけなら,その数に丸める,
- (2) 一番近い丸め結果候補が2つある場合は,末尾が偶数のものに丸める,
- (3) 丸め処理は1段階で行なわなければならない.

例えば小数点以下第1桁に丸めるなら次のようになる.規則 (2) が適用される場合は
通常の四捨五入とは異なる結果になる場合がある.

|丸める数 |12.223 |12.251|12.25 |12.35 |
| 丸め結果 | 12.2 | 12.3 |COLOR(magenta){12.2}|12.4 |
| 適用規則  | (1) | (1) | (2) | (2) |



規則(3)は,例えば 12.345 は直に12.3と丸めるべきであって、まず12.35とし、
それから12.4としてはならないことを主張している.この規則は,丸めによる
誤差が最小になる利点がある.

 > round(122.5)  # 五捨!
 [1] 122
 > round(122.51) # 五入
 [1] 123
 > round(123.5) # 五入
 [1] 124
 > round(122.501) # 五入
 [1] 123
 

計算機ソフトでは,伝統的に通常の四捨五入方式を採用してきた.市販の電卓や
パソコンソフトの丸め処理法は,必ずしもJIS,ISO方式になっていないことも多く,
チェックが必要であるといわれてる.(今入った情報では、Excel の丸め関数は、小学生方式、一方 VBA は IEEE 方式だそうです。)

とはいえ、実際は気にするほどの差ではない (なにかおかしいかな?)

 > test1 <- function () { 
       x <- floor(100*runif(10000000))/10
       y <- round(x)   # JIS, ISO, IEEE 式四捨五入
      mean(abs(x-y))
    }
 > test1()
 [1] 0.2499519
 > test2 <- function () { 
      x <- floor(100*runif(10000000))/10
      y <- oround(x)  # (中間さん作の)世間一般風四捨五入
     mean(abs(x-y))
   }
 > test2()
 [1] 0.250041

絶対値をとらないで平均すると大きな(?)差 (これで安心)。いずれにしても丸めた方が若干大きくなる傾向に注意。

 > test1 <- function () { x <- floor(100*runif(10000000))/10; y <- round(x); mean(x-y)}
 > test1()
 [1] -5.579e-05
 > test2 <- function () { x <- floor(100*runif(10000000))/10; y <- oround(x); mean(x-y)}
 > test2()
 [1] -0.04997603

中間さんの oround 関数へのコメントに答えるべくシミュレーション。最大一万円の買いものを一千万回したとして、消費税込の値段を、普通の四捨五入と、ISO 式でした場合の食い違い総和は

 > test <- function(){
      x <- floor(10000*runif(10000000))
      x <- 1.05*x
      sum(oround(x) -x)}
 > test()
 [1] 249700.4  # 現状方式では25万円消費者がとられすぎ。
 > test <- function(){
      x <- floor(10000*runif(10000000))
      x <- 1.05*x
     sum(round(x) -x)}
 > test()
 [1] 1515.3     # ISO 式!

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS