0.1 + 0.2 は 0.3 ではない。少なくともコンピュータの世界では。この奇妙な現象は、浮動小数点数という数の表現方法に起因する。無限の小数を有限のビットで表現しようとする試みには、必然的に誤差がつきまとう。

浮動小数点 IEEE 754 精度 丸め誤差

なぜ浮動小数点が必要か

整数だけでは、0.5 や 3.14 といった値を表現できない。かといって、すべての小数を正確に表現するには無限のメモリが必要になる。浮動小数点は、有限のビット数で実数を「近似的に」表現する方法である。

IEEE 754

現代のほぼすべてのコンピュータは、IEEE 754 という規格に従って浮動小数点数を表現する。

IEEE 754 の構造

浮動小数点数 = (-1)^符号 × 仮数部 × 2^指数部

・符号部(sign):正負を表す1ビット

・指数部(exponent):2の何乗かを表す

・仮数部(mantissa/fraction):有効数字を表す

ビット数 符号 指数 仮数 有効桁数(10進)
単精度(float) 32 1 8 23 約7桁
倍精度(double) 64 1 11 52 約15桁

精度の問題

10進数の 0.1 は、2進数では無限小数になる(0.0001100110011...)。これを有限ビットで打ち切るため、誤差が生じる。

有名な例:0.1 + 0.2

JavaScriptで 0.1 + 0.2 を計算すると...

結果:0.30000000000000004

0.3 とは等しくない。

特殊な値

IEEE 754 は、通常の数以外にも特殊な値を定義している。

意味 発生例
+∞, -∞ 無限大 1.0 / 0.0
NaN Not a Number 0.0 / 0.0, √(-1)
-0 負のゼロ -1.0 / ∞

NaNの特徴:NaN == NaN は false。自分自身と等しくない唯一の値。

対処法

許容誤差での比較

浮動小数点の等値比較は、許容誤差(epsilon)を使う。

Math.abs(a - b) < epsilon

整数での計算

金額計算では、円ではなく「銭」単位の整数で扱う。1234円50銭 → 123450(整数)

高精度ライブラリ

任意精度演算が必要な場合は、BigDecimal(Java)、Decimal(Python)などを使用。

実務での応用

WEB開発での応用

金額計算:浮動小数点を避け、整数(最小単位)で計算。表示時に変換。

座標計算:地図APIでの緯度経度は倍精度が必要。

アニメーション:累積誤差に注意。フレーム間の差分で計算。

AI/MLでの応用

勾配消失/爆発:極端に小さい/大きい値が累積する問題。

半精度(FP16):メモリ節約のため16ビット浮動小数点を使用。精度とのトレードオフ。

正規化:数値を一定範囲に収めて、精度を保つ。

深掘りリンク