【Java進化史 第6回】数字は読めるようになったのか ― Java7数値リテラルと浮動小数点の現実
Java6までしか知らない50代が、Java7以降をやり直すシリーズ。
今回はJava7で改善された数値リテラルと、
その裏にある浮動小数点の現実について整理する。
■ 昔、数字は読めなかった
昔、数値は「正しければいい」と思っていた。
だが、あとからコードを読むとこうなる。
「これ、何桁だ?」
double amount = 1000000.123456;
double rate = 0.00001234;
- 桁が読みにくい
- 金額か割合か直感で分からない
- コメントが必要になる
ビットマスクも同じだった。
int mask = 8; // 1000?
毎回、頭の中で2進数に変換していた。
■ Java7で何が変わったのか
1. アンダースコアが使えるようになった
double amount = 1_000_000.123_456;
double rate = 0.000_012_34;
桁が視覚的に分かる。
コメントがなくても意味が伝わる。
2. 2進数リテラル(0b)が使えるようになった
int mask = 0b1000;
int flag = 0b0101;
ビットの意味が直接読める。
Java7は、大きな変更だけでなく、
読む人のための改善を入れてきた。
■ しかし ― 浮動小数点の罠
数字が読みやすくなっても、
計算が正確になったわけではない。
0.1 + 0.2 問題
System.out.println(0.1 + 0.2);
出力:
0.30000000000000004
浮動小数点は2進数で近似表現される。
そのため、正確な10進小数にはならない。
■ 浮動小数点どうしの比較は危険
危険な比較
if (a == b) {
// 同じ?
}
閾値(ε)を使う
double EPS = 1e-10;
if (Math.abs(a - b) < EPS) {
// ほぼ同じとみなす
}
実務ではこの考え方が必須になる。
■ 正確な計算が必要なら BigDecimal
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
BigDecimal result = a.add(b);
System.out.println(result); // 0.3
ポイントは文字列で生成すること。
やってはいけない例
BigDecimal x = new BigDecimal(0.1);
System.out.println(x);
出力:
0.1000000000000000055511151231257827021181583404541015625
doubleの誤差をそのまま引き継いでしまう。
安全な書き方
BigDecimal x = new BigDecimal("0.1");
// または
BigDecimal y = BigDecimal.valueOf(0.1);
■ 昔、私はこう信じていた
Javaを習い始めたころ、
「小数点があるなら float や double だろう」と思っていた。
そして見事にハマった。
- 計算はズレる
- 比較は一致しない
- 表示すると変な桁が出る
そのとき初めて知った。
浮動小数点は“正確な小数”ではない。
■ まとめ
| 項目 | float/double | BigDecimal |
|---|---|---|
| 精度 | 近似値 | 正確 |
| 2進数表現 | あり | なし(10進ベース) |
| 比較 | 誤差考慮が必要 | equalsで比較可能 |
| 金融用途 | 不向き | 推奨 |
Java7は数字を読みやすくした。
だが、数字の本質は変わらない。
「数字が読める」ことと
「数字が正しい」ことは別問題である。
0 件のコメント:
コメントを投稿