はじめ
Java の小数点がなかなか理解できず毎回つまづいていたので、
一度ちゃんと整理して“自分メモ”として残しておこうと思います。
Java には小数点を扱う型がいくつかありますが、
今回はとくに混乱しやすい double と float をメインで触っていきます。
型の種類
Java で小数を扱う代表的な型は float と double の2種類です。
違いをざっくり表にまとめると以下の通りです。
[特徴表]
| 種類 | bit数 | 精度 | 速度 | 誤差 | 用途 |
|---|---|---|---|---|---|
| float | 32bit | 約7桁 | やや速い | 出やすい | 古いゲーム・組み込み系 |
| double | 64bit | 約15桁 | 標準 | 出る | Java ではほぼ全部こちら |
float(単精度浮動小数点)
- 小数を扱えるけど、精度はそれほど高く無い
- メモリ使用量が少ない
- 0.1 を正確に表現できない
- 今はメモリが十分あるため、「軽いから float を使う」という理由がほとんど存在しない。
- 細かい計算を繰り返すと誤差が目立つ
- 小数を書くと デフォルトでdouble扱いになるので、fを付ける必要がある
float a = 0.1f;
float b = 0.2f;
System.out.println(a + b);
// => 0.300000012... - 誤差が大きく出る(丸め誤差)
※float を選ぶ理由がない限り、double を使う
double(倍精度浮動小数点)
- 小数を書いたとき 自動的に double として扱われるデフォルトの型
- 小数の誤差が出にくく、より正確に扱える
- 特に科学計算、座標、物理などは基本 double
- float より「正確」だけど、“完全に正確ではない”
double a = 0.1;
double b = 0.2;
System.out.println(a + b);
// => 0.30000000000000004 - 内部では「近い値」に丸められる。(丸め誤差)
[おまけ] 丸め誤差とは?
ある桁以降の値を四捨五入・切り捨て・切り上げて桁を調整することで生じる誤差のズレInt型との扱いの違い
int ÷ int は “整数のまま” 計算される
Java では、int と int の割り算は小数を切り捨てて整数になる。
int a = 5;
int b = 2;
System.out.println(a / b); // 2(小数切り捨て)
小数が欲しい場合の工夫
整数のどちらかを float または double にする
// ①
int a = 5;
int b = 2;
System.out.println(a / (double)b); // 2.5
// ②
System.out.println((double)a / b);
// ③
System.out.println(a / 2.0); // 2.5
キャストの位置
キャストは “計算前” に行うこと
// NG
(double)(a / b); // ここでは a/b が先に整数化される → 2.0 になっちゃう
// OK
(double)a / b; // 割り算が行われる「前」にどちらかを double に変えるのがポイント。
整数にするための工夫
切り上げ・切り捨て・四捨五入をしたいケースは注意が必要
// 切り上げ
int result = (int)Math.ceil((double)a / b);
// 四捨五入
int result = (int)Math.round((double)a / b);
// 切り捨て(デフォルト)
int result = a / b;
まとめ
- float / double はどちらも誤差がある浮動小数点
- 基本は double を使う
- int / int は整数除算になるため、小数が欲しいときは片方を double にする