IEEE 754 浮動小数点標準:コンピュータ算術の仕組み
プログラミングをしていると、奇妙な現象に遭遇することがあります。0.1 + 0.2 が 0.3 に等しくないのです。代わりに、0.30000000000000004 のような結果が返ってきます。これはプログラミング言語のバグではありません。コンピュータが IEEE 754 標準 を使用して実数を表現する方法から生じる、根本的な結果です。
このガイドでは、IEEE 754 標準を分かりやすく解説し、浮動小数点数がどのように保存されるかを説明し、コード内での精度問題の対処法を紹介します。
IEEE 754 とは何か?
IEEE 浮動小数点数演算標準 (IEEE 754) は、浮動小数点演算において最も広く使用されている標準です。1985 年に策定され、実数をバイナリ(2 進数)で表現する形式と、それらに対する演算を定義しています。
最も一般的な形式は以下の通りです。
- 単精度 (32ビット): C/C++/Java の
float。 - 倍精度 (64ビット): C/C++/Java の
double。JavaScript や Python のデフォルトの数値型です。
仕組み:浮動小数点の構造
浮動小数点数は、科学的表記法 ($1.23 \times 10^4$) に似た方法で表現されますが、バイナリ形式です。3 つの部分で構成されています。
- 符号ビット (1ビット):
0は正、1は負。 - 指数部 (Exponent): 数値のスケールを決定。
- 仮数部 (Mantissa/Significand): 有効数字を表現。
64 ビット倍精度レイアウト:
- 符号: 1 ビット
- 指数: 11 ビット
- 仮数: 52 ビット
計算式は以下の通りです。 $(-1)^{sign} \times (1.mantissa) \times 2^{exponent - bias}$
なぜ $0.1 + 0.2 \neq 0.3$ なのか?
根本的な原因は、ほとんどの 10 進小数がバイナリで正確に表現できないことにあります。
- 10 進法では、分母の素因数が 2 と 5(10 の因数)のみの場合、分数は正確に表現できます。
- 2 進法では、分母の素因数が 2 のみの場合に限り、分数は正確に表現できます。
$0.1$ は $1/10$ です。10 には因数 5 が含まれるため、バイナリでは無限に繰り返す配列になります。
0.00011001100110011...
コンピュータは、この無限の配列を 32 ビットまたは 64 ビットに収めるために丸める必要があり、その結果、私たちが目にするような微小な誤差が生じます。
特殊な値
IEEE 754 は、例外的なケースを処理するためにいくつかの特殊な値も定義しています。
- NaN (Not a Number): 不定な演算の結果(例:
0/0)。 - Infinity ($\infty$): オーバーフローや 0 除算の結果(例:
1/0)。 - 負のゼロ (-0): 一部の計算で正のゼロと区別されます。
開発者のためのベストプラクティス
- 浮動小数点の比較に
==を使わない: 常に差が非常に小さい値 (イプシロン) 未満であるかを確認してください。if (Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON) { ... } - お金の計算には定点数を使う: 財務計算には、専用のライブラリ (例:
decimal.js) を使用するか、値を整数(ドルではなくセントなど)として保存してください。 - 範囲に注意する: 倍精度は非常に大きな数値を表現できますが、数値が大きくなるほど精度は低下します。
よくある質問 FAQ
Q: 浮動小数点演算は非決定的ですか? A: 一般的には違います。同じ入力と同じ丸めモードが与えられれば、IEEE 754 は同じ結果を生成します。ただし、コンパイラや CPU 命令 (FMA など) によってわずかな差異が生じることがあります。
Q: "BigInt" とは何ですか? A: JavaScript の BigInt は、任意精度の整数を扱います。小数は扱えません。小数が必要な場合は、Decimal ライブラリが必要です。
Q: 倍精度の 10 進精度の桁数は? A: 64 ビット倍精度は、約 15 ~ 17 桁の有効な 10 進数字を持ちます。
関連ツール
- 単位转换器 - さまざまな測定単位間で正確な変換を行います。
- JSON フォーマッタ - 数値が JSON データでどのように表現されているかを確認します。
- ハッシュジェネレーター - 1 ビットの違いが重要な場合にデータの完全性を検証します。