FE EXAM

丸め誤差

コンピュータが有限のビットで数値を近似する際に生じる誤差。浮動小数点の計算を繰り返すと蓄積されていきます。

ROUNDING ERROR SIMULATOR
期待値
実際値
誤差
期待値
10.000000
実際値
10.000002
絶対誤差
1.907e-6
相対誤差
1.907e-5%
2進表現:0.00011001100110011001100110011001...循環小数(近似)
加算値0.1
加算回数100
11000
プリセット
精度
解説

📌
丸め誤差とは

本当の値0.1₁₀コンピュータ内部0.00011001100...この差 = 丸め誤差

丸め誤差とは、実数を有限のビット数で表現するときに生じるズレのことです。 コンピュータは数値を2進数で保持しますが、多くの10進小数は2進数では無限に続く循環小数になります。 有限ビットに収めるために切り捨てや丸めが行われ、ここでわずかな誤差が発生します。

つまり、10進数で「0.1」と書けるシンプルな数でも、コンピュータの内部では正確に表現できないのです。 これは10進数で 1/3 = 0.333... と無限に続くのと同じ原理です。2進数にとっての「割り切れない数」が10進数の世界では日常的に使われるため、丸め誤差は避けられません。

上のツールで「0.1」を入力すると、内部でどのような2進表現になり、どれだけの誤差が生じるか確認できます。 ステップ数スライダーで加算回数を増やすと、誤差が蓄積されていく様子も観察できます。

🔍
発生する原因

10進 → 2進の変換0.10.0001100110011...循環!0.20.0011001100110...循環!合計:0.30000000000000004 (≠ 0.3)

丸め誤差が生じる根本原因は、「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 の結果特徴
最近接偶数(銀行丸め)24IEEE 754 既定。誤差が正負に偏らない
四捨五入340.5 は常に切り上げ。誤差が +側に偏る
切り捨て(0方向)23小数部を捨てる。常に絶対値が小さく
切り上げ(∞方向)34安全側の見積もりに使う

注目すべきは最近接偶数丸め(銀行丸め)です。ちょうど中間の値(0.5)が来たときに「結果が偶数になるほう」に丸めます。たとえば 2.5 → 23.5 → 4。四捨五入だと 0.5 が必ず切り上がって誤差が +側に偏りますが、最近接偶数丸めでは切り上げと切り下げが均等に起こるので、大量の計算をしても誤差が打ち消し合います。

IEEE 754 のデフォルト丸め方式は最近接偶数丸めです。「四捨五入」と勘違いしやすいので注意しましょう。切り上げ・切り捨て・四捨五入はそれぞれ丸め方向が異なります。

📌
対策方法

整数演算金額を円単位にDecimal型10進で正確に有理数演算分数のまま計算倍精度15桁の精度

丸め誤差を防ぐには、用途に応じて以下の方法を使い分けます:
整数演算に置き換える: 金額を「円」単位の整数で扱えば、小数が出ないので誤差もゼロです。たとえば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進の変換で発生)、桁落ちは「減算」の問題(近い値の引き算で発生)、情報落ちは「桁合わせ」の問題(指数を揃える際に発生)。 それぞれ原因が異なるので、区別して覚えましょう。

練習問題

🎯
基本情報技術者 練習問題

Q1.浮動小数点数で 0.1 + 0.2 の計算結果が正確に 0.3 にならない理由はどれか。
A.CPUの演算速度が遅いため
B.0.1 や 0.2 が2進数で正確に表現できないため
C.メモリ不足により計算が途中で打ち切られるため
D.10進数から2進数への変換アルゴリズムにバグがあるため
Q2.丸め誤差の蓄積を防ぐ対策として適切でないものはどれか。
A.整数演算に置き換える(例: 金額を「円」単位の整数で扱う)
B.Decimal型やBigDecimal型を使う
C.計算回数を増やして平均をとる
D.倍精度浮動小数点数を使う

関連コンテンツ