2026年2月11日水曜日

【Java進化史 第6回】Java7 - 数字は読めるようになったのか ― Java7数値リテラルと浮動小数点の現実

【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 件のコメント:

コメントを投稿

【Java進化史 第10回】Java8 〜あのPermGenはどこへ消えた〜

【Java進化史 第10回】Java8 〜あのPermGenはどこへ消えた〜 昔、意味も分からず書いていたオプションがある。 -XX:MaxPermSize=256m 足りなければ増やす。 512m。 1024m。 それでも、死ぬ。 java.l...