というわけで、端数の丸め処理についてです。
端数処理ということで、たぶん思いつくのは、
- 切り捨て
- 切り上げ
- 四捨五入
こんなところではないかと思います。
ここで、テストデータとして
11.4, 11.5, 11.6, 12.4, 12.5, 12.6
という6つのデータを用意します。
それぞれの処理についてですが、通り下記のようになります。
データ | 切り捨て | 切り上げ | 四捨五入 |
11.4 | 11 | 12 | 11 |
11.5 | 11 | 12 | 12 |
11.6 | 11 | 12 | 12 |
12.4 | 12 | 13 | 12 |
12.5 | 12 | 13 | 13 |
12.6 | 12 | 13 | 13 |
C や C# そして Ruby や Java などでは、実数を整数に丸める際、
単純にキャストしますと切り捨てますが、
round 関数で丸める際に、挙動が異なります。
C や Ruby, Java では四捨五入がデフォルトで行われますが、
C# では、銀行丸めがデフォルトで行われます。
正式名称は 「最近接偶数への丸め」と言いますが、
「銀行丸め」のほか、「JIS丸め」「ISO丸め」とも言われます。
JIS丸めとは?
http://homepage1.nifty.com/s_miyake/hp/jisround.htm
JIS Z 8401
http://www.jisc.go.jp/app/pager?id=94037
上の記事の文章を用いて、簡単に説明すれば、
N桁で丸める場合
第N桁が偶数なら 5以下は切り捨て。それ以外は切り上げ。
第N桁が奇数なら 5未満は切り捨て。それ以外は切り上げ。
この挙動について、
11.5 と 12.5 という2つの値を整数値に丸めるという場合で説明しますと、
まず 11.5 の場合。
整数値に丸めるので、整数第1位に丸めることになります。
この場合、整数第1位の値は 1 となり、「奇数」です。
次にこの一つ下の値を参照し、 5 であるため、奇数で5未満でないため切り上げ。
よって、 12 となります。
次に 12.5 の場合。
同様に整数第1位の値を見ると 2 となり「偶数」です。
一つ下の値は 5 であるため、偶数で5以下のため切り捨て。
よって、12 となります。
ただどうしてこういう丸め方をしているかというと、
主に銀行や統計などにおいて、誤差を小さくするために用いられています。
整数に丸める時の注意 – DiaryException
http://d.hatena.ne.jp/LaclefYoshi/20110430/1304138274
こちらの記事におもしろい実験結果がありますので、参照して頂けたら。
上記ブログで用いられている R という言語は、統計に特化した処理系ですので、
やはり誤差を抑えるために、銀行丸めが行われているものと思われます。
というわけで、先ほどの結果に、銀行丸めと合計を追加すると以下のようになります。
データ | 切り捨て | 切り上げ | 四捨五入 | 銀行丸め |
11.4 | 11 | 12 | 11 | 11 |
11.5 | 11 | 12 | 12 | 12 |
11.6 | 11 | 12 | 12 | 12 |
12.4 | 12 | 13 | 12 | 12 |
12.5 | 12 | 13 | 13 | 12 |
12.6 | 12 | 13 | 13 | 13 |
というわけで、統計やトレードなどを行う場合はありがたいわけですが、
どうしても四捨五入を行わなければならない場合があります。
その場合は、Math.Round(val) としているところを、
Math.Round(val, MidpointRounding.AwayFromZero);
とすることで解決可能です。
ではではー!
ピンバック: 20121111 11月になり流されていると実感 at MeMo
ピンバック: 銀行丸めと四捨五入。いやだからC#でも四捨五入は出来るから | OPC Diary - No Code, No Life.