sh1’s diary

プログラミング、読んだ本、資格試験、ゲームとか私を記録するところ

小数を持つ値の丸め方と、その規則について

小数値の丸めは Math.Round メソッドを利用するのがわかりやすいです。

Math.Round(d, decimals, mode)
d : 数値
decimals : 丸め位置
mode : 丸め方法

ポイントは、丸め方法 Mode です。
丸め方法のModeパラメータは、System.MidpointRounding 列挙体の ToEven or AwayFromZero 引数をとります。

丸め方法の動作は IEEE 規格 754、セクション 4 に従っているので、ISO JIS などもフォロー。 1

Round メソッドを利用する場合には、ToEven と AwayFromZero が丸め方法のうち、何になるのかを理解する必要があります。 JIS8401 規則だと、次のようになっていることを、知るということです。

  • ToEven = JIS 8401 規則A
  • AwayFromZero = JIS 8401 規則B

丸め方の違いを確認する

規則Aと規則Bで丸める挙動が異なるのは、次のケースです。 与えられた数値に等しく近い、2つの隣り合う数値がある場合に挙動が異なります。

例)
数値:10.2345(小数第3位で丸める)
ToEven = 10.234
AwayFromZero = 10.235

var value = 10.2345;
var r1 = Math.Round(value, RoundPos, MidpointRounding.ToEven); // 規則A
var r2 = Math.Round(value, RoundPos, MidpointRounding.AwayFromZero); // 規則B

Excel の挙動

エクセル(2013)のRoundの挙動についても言及しておきます。 これは情報が多いですが、セル上での計算と、VBAでの結果が異なっているようです。

  • セル = JIS 8401 規則B
  • VBA = JIS 8401 規則A

f:id:shikaku_sh:20190227104922p:plain:w400
セル計算と VBA 計算の結果

図のとおり、セル上で =ROUND() で計算した値と、VBA の計算結果が一致しません。

計算誤差に関する問い合わせの多くは、日本だと「Excel で計算したんだけど」から、始まるケースが多いですが、丸め方がそもそも違っていることが少なくないです。
あらかじめ、丸め方の宣言書を提出しておくケースもあります。

サンプルプログラム

小数点以下の丸め方の差を比較するサンプルを公開しています。
「DecimalValueRoundTest」プロジェクトです。

f:id:shikaku_sh:20190227105301p:plain:w300
丸め誤差を確認できる!

参考

Effective C# 6.0/7.0

Effective C# 6.0/7.0

  • 作者:Bill Wagner
  • 発売日: 2018/09/05
  • メディア: 単行本(ソフトカバー)


  1. It conforms to IEEE Standard 754, section 4. (Docs - Math.Round Method)