コンピュータが有限のビットで数値を近似する際に生じる誤差。浮動小数点の計算を繰り返すと蓄積されていきます。
丸め誤差とは、実数を有限のビット数で表現するときに生じるズレのことです。 コンピュータは数値を2進数で保持しますが、多くの10進小数は2進数では無限に続く循環小数になります。 有限ビットに収めるために切り捨てや丸めが行われ、ここでわずかな誤差が発生します。
つまり、10進数で「0.1」と書けるシンプルな数でも、コンピュータの内部では正確に表現できないのです。 これは10進数で 1/3 = 0.333... と無限に続くのと同じ原理です。2進数にとっての「割り切れない数」が10進数の世界では日常的に使われるため、丸め誤差は避けられません。
上のツールで「0.1」を入力すると、内部でどのような2進表現になり、どれだけの誤差が生じるか確認できます。 ステップ数スライダーで加算回数を増やすと、誤差が蓄積されていく様子も観察できます。
丸め誤差が生じる根本原因は、「10進数の小数を2進数の有限ビットで完全に表現できない」ことにあります。代表例として 0.1 + 0.2 ≠ 0.3 になる仕組みを見てみましょう。 10進数の0.1を2進数に変換すると、0.1 × 2 = 0.2、0.2 × 2 = 0.4、0.4 × 2 = 0.8、0.8 × 2 = 1.6、0.6 × 2 = 1.2、0.2 × 2 = 0.4... と0011 のパターンが永遠に繰り返します。 結果として 0.1 の2進表現は0.0001100110011...という無限循環小数です。
同様に 0.2 は0.00110011001100...です。 これらを有限ビット(倍精度なら52ビット)で丸めてから足すと、丸め誤差が合算されて0.30000000000000004になります。 真の値 0.3 との差は約 5.6 × 10-17 ですが、この微小な差が等値比較で問題になります。
これはバグではなく、2進浮動小数点の本質的な特性です。 JavaScript、Python、Java、C など、ほぼすべての言語で同じ結果になります。上のツールで実際に確認してみてください。
「丸める」と一口に言っても、ビット列を切り捨てるときのルールには複数の方式があり、選んだ方式によって誤差の出方や符号が変わります。代表的なのは次の4つです。
| 丸め方式 | 2.5 の結果 | 3.5 の結果 | 特徴 |
|---|---|---|---|
| 最近接偶数(銀行丸め) | 2 | 4 | IEEE 754 既定。誤差が正負に偏らない |
| 四捨五入 | 3 | 4 | 0.5 は常に切り上げ。誤差が +側に偏る |
| 切り捨て(0方向) | 2 | 3 | 小数部を捨てる。常に絶対値が小さく |
| 切り上げ(∞方向) | 3 | 4 | 安全側の見積もりに使う |
注目すべきは最近接偶数丸め(銀行丸め)です。ちょうど中間の値(0.5)が来たときに「結果が偶数になるほう」に丸めます。たとえば 2.5 → 2、3.5 → 4。四捨五入だと 0.5 が必ず切り上がって誤差が +側に偏りますが、最近接偶数丸めでは切り上げと切り下げが均等に起こるので、大量の計算をしても誤差が打ち消し合います。
IEEE 754 のデフォルト丸め方式は最近接偶数丸めです。「四捨五入」と勘違いしやすいので注意しましょう。切り上げ・切り捨て・四捨五入はそれぞれ丸め方向が異なります。
丸め誤差を防ぐには、用途に応じて以下の方法を使い分けます:
・整数演算に置き換える: 金額を「円」単位の整数で扱えば、小数が出ないので誤差もゼロです。たとえばprice = 1980(円単位の整数)として計算します。
・Decimal型 / BigDecimal型: 10進数を正確に扱える専用の型です。Pythonならfrom decimal import Decimalで利用できます。
・有理数演算: 分数(分子/分母)のまま計算し、最後に10進に変換します。Pythonのfractions.Fractionなどが該当します。
・倍精度を使う: 単精度(約7桁)から倍精度(約15桁)に変えるだけでも誤差が大幅に減ります。ただし根本解決ではなく、誤差が小さくなるだけです。
金融システムでは整数演算またはDecimal型が必須です。「1円のずれ」が許されない世界では、浮動小数点数をそのまま使うのは危険です。 科学技術計算では倍精度+Kahan加算の組み合わせがよく使われます。
| 丸めモード | 0.5の扱い | 用途 |
|---|---|---|
| 最近接偶数丸め(銀行丸め) | 偶数側に丸める | IEEE 754 デフォルト |
| 四捨五入 | 常に切り上げ | 一般的な計算 |
| 切り捨て(0方向) | 小さい方に丸める | 整数除算 |
| 切り上げ(∞方向) | 大きい方に丸める | 安全側の見積もり |
IEEE 754のデフォルトは最近接偶数丸め(銀行丸め)です。 ちょうど中間の値(0.5)のとき、四捨五入のように常に切り上げるのではなく、結果が偶数になるほうに丸めます。 たとえば 2.5 は 2 に、3.5 は 4 に丸められます。
なぜこの方式がデフォルトなのでしょうか?四捨五入では 0.5 が常に切り上げられるため、多数の計算で誤差が正の方向に偏ります。 最近接偶数丸めでは切り上げと切り下げが均等に起こるため、誤差の偏りがなくなり、統計的に最も正確な結果が得られます。
| 種類 | 発生条件 | 原因 |
|---|---|---|
| 丸め誤差 | 常に発生しうる | 有限ビットへの変換時に切り捨て |
| 桁落ち | ほぼ等しい値の減算 | 上位桁が相殺され有効桁が激減 |
| 情報落ち | 大きさが極端に違う値の加算 | 小さい方の値が丸められて消える |
| オーバーフロー | 表現可能範囲を超える | 指数部の上限を超えた |
丸め誤差・桁落ち・情報落ちはそれぞれ別物として区別しておくことが大切です。 丸め誤差は「有限ビットに収める際の誤差」ですべての浮動小数点演算で起こりうる最も基本的な誤差です。 一方、桁落ちや情報落ちは特定の条件(近い値の減算、大小差のある加算)でのみ発生する誤差です。
覚え方のポイント: 丸め誤差は「変換」の問題(10進→2進の変換で発生)、桁落ちは「減算」の問題(近い値の引き算で発生)、情報落ちは「桁合わせ」の問題(指数を揃える際に発生)。 それぞれ原因が異なるので、区別して覚えましょう。