Code Fix

中級

整数同士の割り算で小数が消える理由

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が今から/の意味を変えることは後方互換性の観点から現実的ではなく、この挙動は今後も変わりません。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)