浮動小数点数の丸め誤差(限界) について解説します。これは実際にプログラムを書いていくと必ず出会う落とし穴です。
1. 丸め誤差とは?
コンピュータは数値を 2進数(0と1) で表現します。
ところが、10進数で「きれいに表せる数」でも、2進数では無限に続いてしまう場合があります。
例:
- 10進数の
0.1は、2進数では 無限小数 になる - コンピュータは有限の桁数しか扱えないので、途中で切り捨てて保存する
→ これが 丸め誤差 です。
2. 実際の例題
例1: 0.1 を足していく
class Example7 {
public static void main(String[] args) {
double x = 0.1 + 0.1 + 0.1;
System.out.println(x);
}
}
Java👉 出力: 0.30000000000000004
本当は 0.3 になるはずが、誤差が出ています。
例2: 比較の落とし穴
class Example8 {
public static void main(String[] args) {
double a = 0.1 * 3;
double b = 0.3;
System.out.println(a == b);
}
}
Java👉 出力: false0.1 * 3 と 0.3 は理論上同じはずですが、内部表現の誤差で一致しません。
3. 誤差への対処法
- 比較するときは「許容範囲」を決める
double a = 0.1 * 3;
double b = 0.3;
double epsilon = 1e-9; // 許容誤差
if (Math.abs(a - b) < epsilon) {
System.out.println("ほぼ等しい");
}
Java👉 誤差を考慮して「ほぼ等しい」と判定する。
- お金の計算など正確さが必要な場合は BigDecimal を使う
import java.math.BigDecimal;
class Example9 {
public static void main(String[] args) {
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = a.multiply(new BigDecimal("3"));
System.out.println(b); // 0.3
}
}
Java👉 BigDecimal は文字列ベースで計算するので誤差が出ない。
まとめ
- 浮動小数点数は 内部的に近似値 で表現されるため、誤差が出ることがある
==で直接比較するのは危険- 誤差を許容するか、正確さが必要なら BigDecimal を使う
