整数同士の割り算で小数が消える理由
int / int はintで計算されます。キャストの位置による結果の違いを扱います。
なぜエラーが出ないのか
出力: 2.0
(エラーなし)- javacは何も報告しません。文法として正しいためです
出力: 2.0- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 public class Main { 2 public static void main(String[] args) { 3 int a = 5; 4 int b = 2; 5 double r = a / b; ^ 6 System.out.println(r); 7 } 8 }
出力: 2.0期待: 2.5 (コンパイルは通っています)
int同士の割り算はintで計算され、小数が切り捨てられます。割る前にキャストが要ります。
直し方: a を (double) a にします。
広告
広告スロット(未設定)
パターン2
1 public class Main { 2 public static void main(String[] args) { 3 int correct = 3; 4 int total = 7; 5 System.out.println(correct * 100 / total + "%"); ^ 6 } 7 }
出力: 42%期待: 42.857142857142854% (コンパイルは通っています)
どこか1箇所をdoubleにすると式全体がdoubleで計算されます。掛ける順序でも結果が変わります。
直し方: 100 を 100.0 にします。
パターン3
1 public class Main { 2 public static void main(String[] args) { 3 int[] scores = {70, 85, 90}; 4 int sum = scores[0] + scores[1] + scores[2]; 5 double average = sum / scores.length ; ^ 6 System.out.println(average); 7 } 8 }
出力: 81.0期待: 81.66666666666667 (コンパイルは通っています)
sumもscores.lengthもint型なので、割り算の結果もintになります。どちらかをdoubleにキャストしてから割ります。
直し方: scores.length を (double) scores.length にします。
パターン4
1 public class Main { 2 public static void main(String[] args) { 3 int correct = 2; 4 int total = 5; 5 double rate = correct * 1 / total; ^ 6 System.out.println(rate); 7 } 8 }
出力: 0.0期待: 0.4 (コンパイルは通っています)
1.0を掛けるとその時点で式全体がdoubleに昇格します。整数リテラルの1のままでは効果がありません。
直し方: 1 を 1.0 にします。
パターン5
1 public class Main { 2 public static void main(String[] args) { 3 int seconds = 90; 4 double minutes = seconds / 60 ; ^ 5 System.out.println(minutes); 6 } 7 }
出力: 1.0期待: 1.5 (コンパイルは通っています)
分母をdoubleリテラルにするだけでも、式全体がdoubleで計算されるようになります。
直し方: 60 を 60.0 にします。
よくある誤解
結果をdoubleで受けても手遅れです。割り算が終わったあとに変換しても、切り捨てられた小数は戻りません。
実務での勘所
int同士の演算結果がintになるのはJava独自の癖ではなく、C/C++/C#など「Cファミリー」と呼ばれる言語群が共通して採用している二項数値昇格のルールです。Python 3は、まさにこの種の初学者のつまずきを避けるため、/を常に小数の割り算にし、切り捨てが必要な場合は//という別の演算子を用意する設計に変えました。Javaが今から/の意味を変えることは後方互換性の観点から現実的ではなく、この挙動は今後も変わりません。