配列の平均
合計までは出せるようになりました。ところが 3 点と 4 点の平均を出そうとすると、画面に出るのは 3.5 ではなく 3.0 です。式は合っているのに答えだけ違う、という一番気持ちの悪い種類のバグです。
3.5 が 3.0 になる
原因は割り算そのものにあります。Java では int どうしの割り算の結果も int になります。小数点以下は四捨五入ではなく切り捨てです。
Java
int total = 7;
int count = 2;
double avg = total / count;
System.out.println(avg); // 3.0double avg と受け皿を小数にしても手遅れです。右辺の total / count は int どうしなので、先に 3 が確定します。そのあと double に入れ直しても、消えた 0.5 は戻ってきません。
割り算をする前に小数にしておく
直し方は、割る前に片方を double に変えておくことです。型の変換をその場で命じる書き方を キャスト と呼び、変えたい型を丸カッコで包んで値の手前に置きます。
Java
int total = 7;
int count = 2;
System.out.println((double) total / count); // 3.5
System.out.println((double) (total / count)); // 3.0上と下で結果が変わるのは、キャストの位置が違うからです。上は total だけを 7.0 に変えてから割っています。片方が double になると、もう片方も自動で double に引き上げられるので、答えも小数のままです。下は丸カッコの中の int どうしの割り算が先に終わってしまい、切り捨て済みの 3 を小数にしているだけです。
意味があるのは割り算より前に置いたキャストだけ、と覚えてください。
0 で割ると、そこで止まる
もうひとつ、割り算には落ちどころがあります。分母が 0 のときです。
Java
int total = 7;
int people = 0;
System.out.println(total / people); // ArithmeticException: / by zeroint の割り算で分母が 0 になると、ArithmeticException が投げられてプログラムはその場で止まります。1 件もデータが無いのに平均を出そうとしたときに、これが起きます。
防ぎ方は、割り算にたどり着く前に引き返すことです。
Java
if (people == 0) {
System.out.println("対象がいないので計算できません");
return;
}このように、おかしな入力をメソッドの入り口で弾いて先へ進ませない書き方を ガード節 と呼びます。処理の本体が if の入れ子で深くならないので、読みやすさの面でも得をします。
やってみよう
arrayAvg は int[] を受け取って平均を double で返すメソッドです。作る順番は次のとおりです。
- 要素が 1 つも無いときにここから先へ進ませないガード節を、メソッドの先頭に置く。このときの戻り値は
0.0と決まっています - 前回と同じ要領で、ループを回して合計を作る
- 合計を要素数で割る。キャストを置く位置を間違えないこと
書けたら {4, 7} を渡してみてください。5.5 が返れば、キャストが正しい位置に入っています。5.0 が返ったら、丸カッコが割り算全体を包んでしまっていないか見直しましょう。
要件
- クラス名は
Solution、メソッド名はarrayAvgで、引数はint[] arr、戻り値はdouble - 空配列 (
arr.length == 0) のときは0.0を返すこと (0 除算しない) - 割り算は
(double) sum / arr.lengthのようにdoubleにキャストしてから行い、整数除算にならないようにすること
入出力例
arrayAvg([4,6]) → 5
arrayAvg([2,2,2]) → 2
arrayAvg([]) → 0
arrayAvg([10,20,30,40]) → 25