Visualizing Roundings
数値計算のプログラムを行うとき、端数処理に関して繰り返し調べていることに気が付きました。負の数の扱いや絶対値を伴った計算は意外に複雑で、気が付くとWikipediaのRoundingやFloor and ceiling functionsを何度も訪れていたり...そこで備忘録として、切り捨てと切り上げ、最近接丸めを図にまとめてみました。
以下は切り捨てと切り上げについてまとめたものです(高解像度版はこちら)。
以下は最近接丸めについてまとめたものです(高解像度版はこちら)。
さて、プログラムで四捨五入を扱ったことがある方は、一度は以下のような実装を行ったことがあるのではないでしょうか。
int q = (int)(y + 0.5);
intへの型変換を利用して四捨五入を行うこの技法は大変ポピュラーですが、yが負である場合に大きな誤りを生むことはあまり知られていません。例えば、-2を四捨五入した結果は-1となります。これはおかしいですよね。視覚化すると以下のようになります。
yが正である場合の結果を変えたくないのであれば、intへの型変換の代わりに床関数を使用します(この実装はRound half upとなります)。
int q = (int)floor(y + 0.5);
これに加え、C言語であればroundやrint、Pythonであればroundを用いることを検討してみましょう。視覚化されているように、roundとrintでは異なる最近接丸めとして実装されている系もあるでしょうし、Python 2とPython 3のroundでは採用されている最近接丸めの手法が異なるため、注意が必要です。
何れにしても扱う問題に応じた手法を選択することが大事でしょう。
参考
このエントリをまとめるにあたり、参考にしたページは以下です。
- Rounding - Wikipedia, the free encyclopedia(端数処理 - Wikipedia)
- Floor and ceiling functions - Wikipedia, the free encyclopedia(床関数と天井関数 - Wikipedia)
- IEEE 754-1985 - Wikipedia, the free encyclopedia(IEEE 754 - Wikipedia)
- IEEE 754-2008 - Wikipedia, the free encyclopedia
- Nearest integer function - Wikipedia, the free encyclopedia
- Half-integer - Wikipedia, the free encyclopedia(半整数 - Wikipedia)
- Sign function - Wikipedia, the free encyclopedia(符号関数 - Wikipedia)
- Modulo operation - Wikipedia, the free encyclopedia
検証に用いたコードは以下の環境で作成しました。