1. 小数
たとえば、最も簡単な電卓を書こうとする場合や、計算が必要なあらゆるプログラム(お金の単純な集計から高度な物理シミュレーションまで)でも同じです。現実の世界では、すべてが整数というわけではありません。これはどうしようもありません。
では、新しいデータ型を身につけましょう!
プログラミングでは、小数は 実数、あるいは 浮動小数点数(floating-point)とも呼ばれます。Java を含む多くの言語では、整数だけでなく「小数」の値、たとえば 3.14、-28.57、2.718281828 などを保持するために使います。
浮動小数点数には主に2種類があります:
| 型 | 表すもの | 値の範囲(概算) | 精度 | 典型サイズ |
|---|---|---|---|---|
|
数値 | ±1.5 × 10-45 ... ±3.4 × 1038 | 小数点以下約7桁 | 4 バイト |
|
数値 | ±5.0 × 10-324 ... ±1.7 × 10308 | 小数点以下約15–16桁 | 8 バイト |
型 float
float 型という名前は floating-point number(浮動小数点数)に由来します。数学における実数には特定の性質がありますが、コンピューターには多くの制約があります。そのため、Java の小数を「実数」と呼ぶのは厳密には適切ではありません。ここでは「浮動小数点数」という呼び名を使います。
float 型は通常、有効数字 7 桁(例: 0.1234567)と 10 の指数部を持ち、メモリを 4 バイト使用します。正確な計算には不十分なため、一般には倍精度の利用が主流です。
型 double
double 型という名前は 倍精度(double precision)に由来します。メモリでは 8 バイト(float の 2 倍)を占め、有効数字は最大 15 桁まで保持できます: 0.123456789012345。小数の計算の大半には十分なので、Java では double が小数を扱う基本型です。
この講義では主に double 型に焦点を当てます。いわゆる「一般的な」小数には既定で double を使うことが推奨されます。ただしこの後で float 型についても取り上げます。
2. double 型変数の宣言と初期化
基本は int と同じですが、ここでは double を使います。
// 変数を宣言し、円周率の値を代入する
double pi = 3.1415926;
// 初期化なしで宣言だけも可能
double averageSalary;
averageSalary = 91234.56;
// 計算もできる!
double pizzaPieces = 8;
double friends = 3;
double piecesPerFriend = pizzaPieces / friends; // 2.666...(2 ではない)
構文上の注意点:
- 小数点の区切りには ピリオド(3.14)を使います。カンマを使うとコンパイルエラーになります!
- 厳密には、double d = 3; と書いてもエラーにはなりません。型は自動的に変換され(整数は損失なく「浮動小数点数」に変わります)。
3. Scanner を使った小数の入出力
まずは小数を出力してみましょう:
double amount = 42.75;
System.out.println(amount); // 出力: 42.75
問題ありません。では、文字列を足すとどうなるでしょうか:
System.out.println("あなたの口座残高: " + amount + " ユーロ。"); // 出力: あなたの口座残高: 42.75 ユーロ。
キーボードからの入力
double を入力するには、Scanner クラスの専用メソッド console.nextDouble() を使います。
Scanner console = new Scanner(System.in);
System.out.println("外の気温を入力してください:");
double temperature = console.nextDouble(); // そのまま double を読み込む
System.out.println("現在の外気温: " + temperature + " 度です。");
4. double の実践: 算術演算
おなじみの演算(+、-、*、/)は、int と同様に使えます:
double distance = 100.5;
double time = 2.0;
double speed = distance / time; // 50.25
System.out.println("平均速度: " + speed); // 平均速度: 50.25
基本はこれだけです。唯一の違いは、オペランドの少なくとも一方が double の場合、除算の結果は常に小数になることです。
int と比較
int a = 5, b = 2;
System.out.println(a / b); // 2(端数は切り捨て)
double aa = 5, bb = 2;
System.out.println(aa / bb); // 2.5
5. double を扱うときの典型的な誤りや「癖」
入力の変換エラー
典型的な状況です。ユーザーは 3,14 を入力しますが、プログラムは 3.14 を期待しています。Java の Scanner.nextDouble() は現在の ロケールに依存します。ロシア語/ドイツ語のロケールではカンマが許容され、英語のロケールではピリオドが必要です。必要に応じて Scanner のロケールを設定するか、文字列として読み込んで手動でパースしてください。
// Locale.US では、入力が「3,14」だと問題になります
double value = console.nextDouble();
コンピューターにおける「不正確さ」の問題
ここで初心者はたいてい少し戸惑います:
double x = 0.1 + 0.2;
System.out.println(x); // えっ… 0.30000000000000004
これは、コンピューター内部での小数表現の「不思議」に遭遇したということです。多くの数値は 2 進法では厳密に表現できません。多くのアプリケーションでは通常それほど問題になりませんが、金融や精密な科学計算では注意が必要です。
6. 重要: double と int — 暗黙的変換と明示的キャスト
整数と小数を足したり、int を double に代入しても、エラーにはなりません:
int i = 2;
double d = i; // 問題なし!
System.out.println(d); // 2
double dd = 3.7;
int ii = (int) dd; // double から int へは明示的にキャストが必要!
System.out.println(ii); // 3(小数部分は切り捨て)
よくある驚き: なぜキャストしたら小数部分が消えるのか? それは int 型が小数を保持できないからです(小数点以下はすべて切り捨てられます)。
double を int に変換する方法や演算子 (int) の詳細は、次回の講義で扱います。
7. フォーマット付き出力: きれいに double を表示する
既定のままだと、double が余分な桁まで表示されることがあります。出力を整形しましょう:
double temp = 23.56789;
System.out.println(temp); // 23.56789
// 小数点以下 2 桁
System.out.println(String.format("%.2f", temp)); // 23.57
// 小数点以下 1 桁
System.out.println(String.format("%.1f%n", temp)); // 23.6
| フォーマット | 結果 | 説明 |
|---|---|---|
|
23.57 | 小数点以下 2 桁の数 |
|
23.6 | 小数点以下 1 桁の数 |
8. float と double のよくあるミス
エラー1: double を float に暗黙変換しようとする
float f = 1.23; // エラー!
コンパイラはこう警告します。「double を float に入れようとしています。精度を失う可能性があります!」 いつも接尾辞 f を付けましょう。
エラー2: int 同士の除算は int の結果であることを忘れる
int a = 7, b = 2;
double result = a / b; // 3.0(3.5 ではない)
小数部分を得るには、少なくとも一方のオペランドを明示的に変換します:
double result = (double) a / b; // 3.5
エラー3: 小数の比較
浮動小数点数を等値比較に == で使わないでください。小さな許容誤差(epsilon)を用いた比較を行いましょう。
エラー4: float の精度喪失
大きな数値や高精度の値を float に保持しないでください。壊れたり、重要な桁を失ったりすることがあります。
GO TO FULL VERSION