経緯
今日も何の気なしに変数の型に合うようコード整理をしていました。
代入される側の変数の型がIntegerだったので、Math.Round()を使って四捨五入をしたつもりでコミットすると、無口な先輩がすっ飛んできました。
「銀行丸めって知ってる?」
銀行丸め(bankers' rounding)
四捨五入 ではほしい桁より下の桁の値が5なら切り上げますが、銀行丸め では切り捨てと切り上げのうち結果が偶数となる方へ丸めます。例えば2.5を銀行丸めすると2になります。
銀行丸め自体はJISやISOの規格の1つだそうです。
なぜ銀行丸めをするかというと記事「銀行家の丸め」とは何か より
何度も何度も丸めをした場合に数値の総合計のズレが少なくなるように
と、各値よりも合計値でのズレに重きを置いてるみたいですね。
Round関数
私が使った Math.Round(Double) はまさに銀行丸めで、四捨五入ではありませんでした。
やりたいこととしては Round(Double, MidpointRounding) を使用して2つ目の引数でMidpointRounding.AwayFromZero を指定すべきでした。
まとめ
「Round関数は名前の通り、四捨五入でしょ」と思い込んだのが悪かったです。
ちゃんと公式ドキュメントを確認します。