Java道|異なる型の演算

数字だけを見ていると、結果を読み違える。
Javaの演算では「どの型で計算されるか」が結果を決める。

Javaでは、数値を使った計算がよく出てきます。足し算、引き算、掛け算、割り算などは、プログラムの中でもとても基本的な処理です。

ただし、Javaで計算するときは、数字そのものだけでなく、型にも注目する必要があります。

たとえば、3 という値でも、int 型として扱うのか、double 型として扱うのかで、計算のされ方が変わることがあります。特に、整数どうしの割り算では、期待していた小数の結果にならないことがあるので注意が必要です。

Javaは型をしっかり区別して扱う言語です。そのため、演算するときにも「どの型の値どうしで計算しているのか」が大切になります。異なる型どうしで演算する場合は、Javaが大きな型へそろえてから計算してくれます。一方で、同じ型どうしの演算では、その型のまま計算されるため、結果が思ったものと違うことがあります。この記事では、指定内容に沿って Sample10.java、Sample11.java(同じ型同士)、Sample11.java(修正後)のみを使い、「異なる型の演算」を鬼滅の刃風の世界観にたとえながら解説します。

鬼滅の刃風にたとえると、型は「技を出すための呼吸の流派」のようなものです。int 型は整数だけを扱う堅実な型、double 型は小数まで扱える広い型です。異なる流派の力を組み合わせるとき、Javaはより広く受け止められる型にそろえてから技を発動します。

異なる型どうしで演算する

まずは、異なる型どうしで演算する場合を見ていきます。

Javaでは、四則演算などで異なる型の値を一緒に使うと、基本的にはより大きな型にそろえてから演算します。

たとえば、int 型と double 型を掛け算する場合です。

ファイル名:Sample10.java

class Sample10
{
    public static void main(String[] args)
    {
        int count = 3;
        double price = 2.5;

        // 護符の個数と単価をかけて合計金額を求める
        System.out.println("護符を " + count + " 個買います。");
        System.out.println("合計金額は " + (count * price) + " 円です。");
    }
}

実行結果

護符を 3 個買います。
合計金額は 7.5 円です。

このプログラムでは、count は int 型です。

int count = 3;

一方、price は double 型です。

double price = 2.5;

そして、次の式で掛け算をしています。

count * price

ここでは、int 型の count と double 型の price を掛け算しています。
型が違いますが、Javaではこの計算ができます。

理由は、int 型の 3 が double 型の 3.0 に変換されてから計算されるからです。

つまり、Javaの内部では次のようなイメージで計算されます。

3.0 * 2.5

その結果、答えは 7.5 になります。

元の型演算前の扱い
count = 3intdouble の 3.0 に変換される
price = 2.5doubleそのまま使われる
結果の型結果
count * pricedouble7.5

鬼滅の刃風にたとえると、int 型の count は「整数だけを扱う基礎の型」、double 型の price は「小数まで扱える広い型」です。2つの力を合わせて技を出すとき、Javaはより広い double 型の呼吸に合わせてから計算します。

なぜ大きい型にそろえるのか

Javaが異なる型どうしを演算するときに、大きい型へそろえるのは、情報を失わないようにするためです。

今回の例では、次の2つを掛け算しています。

変数
countint3
pricedouble2.5

double 型は小数を扱えます。
そのため、int 型の 3 を double 型の 3.0 として扱っても、情報はほとんど失われません。

一方で、もし double 型の 2.5 を int 型に合わせて 2 にしてしまうと、小数部分の .5 が消えてしまいます。
そうすると、計算結果も変わってしまいます。

もし int にそろえた場合結果
3 * 26
double にそろえた場合結果
3.0 * 2.57.5

Javaは、できるだけ情報を失わないように、大きな型へそろえてから計算します。

鬼滅の刃風にたとえると、小さな器の力を大きな器へ移すのは安全です。けれど、大きな器の力を小さな器へ無理に押し込むと、あふれてしまう力があります。Javaはそのあふれを避けるために、大きな型へそろえます。

図:int と double の演算では double にそろう

↓クリックすると拡大表示されます。

この図が示していること

この図では、int 型の count = 3 と double 型の price = 2.5 を掛け算するときの流れを示しています。

まず、int 型の 3 が double 型の 3.0 に自動変換されます。
そのあと、3.0 * 2.5 として計算されます。
結果は double 型の 7.5 になります。

ここから分かることは、Javaが異なる型をそのまま無理に計算しているのではなく、先に型をそろえてから演算しているということです。

同じ型どうしで演算する

次に、同じ型どうしで演算する場合を見ていきます。

同じ型どうしなら分かりやすそうに見えますが、ここには注意点があります。
特に、int 型どうしの割り算です。

次のプログラムを見てください。

ファイル名:Sample11.java(同じ型同士)

class Sample11
{
    public static void main(String[] args)
    {
        int total = 7;
        int people = 2;

        // 7を2で割った結果をdouble型へ代入する
        double result = total / people;

        System.out.println("7個の握り飯を2人で分けた結果は " + result + " 個です。");
    }
}

実行結果

7個の握り飯を2人で分けた結果は 3.0 個です。

ここで、3.5 になると思った人もいるかもしれません。

7 ÷ 2 なので、数学的には 3.5 です。
しかし、Javaでは 3.0 と表示されます。

理由は、割り算に使っている total と people が、どちらも int 型だからです。

int total = 7;
int people = 2;

そして、次の式で割り算しています。

total / people

これは int 型どうしの割り算です。

Javaでは、int 型どうしの割り算は int 型として計算されます。
そのため、7 / 2 の結果は 3 になります。

小数部分の 0.5 は切り捨てられます。

そのあとで、3 が double 型の result に代入されます。
double 型に入るので、表示は 3.0 になります。

処理結果
total / peopleint / int3
double result = 3;int から double へ代入3.0

ここで大切なのは、代入先が double 型でも、計算そのものが double 型になるわけではないということです。

鬼滅の刃風にたとえると、計算の時点では int 型の隊士同士で技を出しています。あとから double 型の巻物に結果を書き込んでも、すでに技の結果は整数の 3 として決まっています。

なぜ 3.5 ではなく 3.0 になるのか

もう少し丁寧に流れを追ってみましょう。

double result = total / people;

この1行を見ると、result が double 型なので、小数の 3.5 が入りそうに感じます。

しかし、Javaでは右辺が先に計算されます。

total / people

この時点で、total も people も int 型です。

変数
totalint7
peopleint2

そのため、計算は int 型どうしの割り算になります。

7 / 2

int 型どうしの割り算では、小数部分は扱われません。
結果は 3 です。

そのあとで、3 が double 型の result に代入されます。
そのため、3.0 と表示されます。

順番処理結果
1total / people を int 型として計算3
23 を double 型の result に代入3.0

つまり、3.5 にならない理由は、代入先の型ではなく、演算に参加している値の型にあります。

図:int / int は整数の結果になる

この図が示していること

この図では、int 型の total = 7 と int 型の people = 2 を割り算したときの流れを示しています。

total / people は int 型どうしの割り算です。
そのため、7 / 2 の結果は 3 になります。
小数部分の 0.5 は切り捨てられます。

そのあとで、3 が double 型の result に代入されるため、表示は 3.0 になります。

ここから分かることは、代入先の型よりも、演算に参加しているオペランドの型が結果を左右するということです。

3.5 の結果を得るにはどうすればよいか

7 ÷ 2 の結果を 3.5 にしたい場合は、割り算を double 型として行う必要があります。

そのためには、演算の前に少なくとも一方の値を double 型に変換します。

ここでは、キャストを使って total と people を double 型に変換します。

ファイル名:Sample11.java(修正後)

class Sample11
{
    public static void main(String[] args)
    {
        int total = 7;
        int people = 2;

        // キャストしてdouble型として割り算する
        double result = (double)total / (double)people;

        System.out.println("7個の握り飯を2人で分けた結果は " + result + " 個です。");
    }
}

実行結果

7個の握り飯を2人で分けた結果は 3.5 個です。

今度は、期待どおり 3.5 になりました。

ポイントは、次の部分です。

(double)total / (double)people

このように書くと、total と people が double 型として扱われます。
つまり、Javaの内部では次のようなイメージになります。

7.0 / 2.0

この場合、double 型どうしの割り算なので、結果は 3.5 になります。

計算時の型結果
total / peopleint / int3
(double)total / (double)peopledouble / double3.5

なぜキャストすると結果が変わるのか

キャストによって、演算に参加する値の型が変わるからです。

double result = (double)total / (double)people;

この式では、まず total と people を double 型に変換しています。

元の値キャスト後
total = 77.0
people = 22.0

そのあとで、double 型どうしの割り算をします。

7.0 / 2.0

double 型は小数を扱えるので、結果は 3.5 になります。

ここで大切なのは、キャストは代入のあとではなく、演算の前に効いているということです。
演算の前に double 型へ変換しているから、小数を含む割り算ができます。

鬼滅の刃風にたとえると、int 型のままでは整数の型でしか技が出せません。けれど、戦う前に double 型の呼吸へ切り替えることで、小数まで含めた細かな力加減ができるようになります。

片方だけを double 型にしてもよい

実は、両方を double 型にキャストしなくても、片方だけ double 型にすれば小数の結果を得られます。

たとえば、次のように書けます。

double result = (double)total / people;

または、次のように書くこともできます。

double result = total / (double)people;

どちらの場合も、片方が double 型になっています。
Javaでは異なる型どうしで演算すると、大きい型にそろえてから計算されます。

そのため、もう片方の int 型も double 型に変換され、double 型の割り算になります。

書き方計算時のイメージ結果
(double)total / (double)people7.0 / 2.03.5
(double)total / people7.0 / 2.03.5
total / (double)people7.0 / 2.03.5

このように、少なくとも一方を double 型にすれば、小数を含む結果を得られます。

異なる型どうしの演算と同じ型どうしの演算の違い

ここまでの内容を整理すると、次のようになります。

パターン計算のされ方結果
異なる型どうしint * doubledouble にそろえて計算double 型の結果
同じ型どうしint / intint のまま計算int 型の結果
int / int を小数で出したい(double)int / intdouble に変換してから計算double 型の結果

Javaでは、演算に参加する値の型がとても重要です。

たとえば、次の式は int 型どうしの割り算です。

7 / 2

結果は 3 です。

一方で、次の式は double 型を含む割り算です。

7.0 / 2

この場合、2 も double 型にそろえられて、7.0 / 2.0 として計算されます。
結果は 3.5 です。

型の見方結果
7 / 2int / int3
7.0 / 2double / int → double / double3.5
7 / 2.0int / double → double / double3.5

数字だけを見ると似ていますが、型が違うと結果も変わります。

よくあるつまずきポイント

異なる型の演算では、次のような点でつまずきやすいです。

つまずきやすい点実際のポイント
double 型の変数に代入すれば小数になると思ってしまう演算の時点で int / int なら結果は整数になる
7 / 2 は 3.5 になると思ってしまうint 型どうしなら結果は 3
キャストは代入時だけに使うと思ってしまう小数で計算したいなら演算前にキャストする
片方だけ double では足りないと思ってしまう片方が double なら、もう片方も double にそろえられる
数字だけを見て判断してしまう型を見ることが大切

特に大切なのは、次の考え方です。

double result = total / people;

この式では、代入先の result は double 型です。
しかし、右辺の total / people は int 型どうしの演算です。

そのため、まず int 型の結果 3 が作られます。
そのあとで、3 が double 型に変換されて 3.0 になります。

小数の 3.5 が欲しい場合は、演算の前に double 型へ変換します。

double result = (double)total / people;

このように書けば、double 型の割り算として扱われるため、結果は 3.5 になります。

型を意識すると計算の意味がよく分かる

Javaで数値計算をするときは、数字そのものだけではなく、その数字がどの型として扱われているかを見ることが大切です。

同じ 7 と 2 を使っていても、型によって結果は変わります。

計算結果理由
int の 7 / int の 23int 型どうしなので整数の割り算になる
double の 7.0 / int の 23.5double 型にそろえて計算される
int の 7 / double の 2.03.5double 型にそろえて計算される

Javaは、ただ数字を計算しているのではありません。
型のルールに従って、どのような型として計算するかを決めています。

鬼滅の刃風にたとえると、同じ技でも、どの呼吸の型で放つかによって威力や表現が変わります。Javaでも、同じ数字を使っていても、int 型で計算するのか、double 型で計算するのかで結果が変わります。

実用的な考え方

実際のプログラムでは、割り算で平均値や割合を求める場面がよくあります。

たとえば、点数の平均、人数で割った金額、割合の計算などです。
このような場面では、小数の結果が必要になることが多いです。

そのときに、int 型どうしで割り算してしまうと、小数部分が消えてしまいます。

int total = 7;
int people = 2;

double result = total / people;

この書き方では、result は 3.0 になります。

小数の 3.5 が必要なら、次のようにします。

double result = (double)total / people;

または、

double result = total / (double)people;

このように、演算の前に少なくとも一方を double 型にしておくことが大切です。

覚えておきたいポイント

ポイント内容
異なる型どうしの演算大きい型にそろえてから計算される
int と double の演算int が double に変換される
結果の型大きい型にそろった結果になる
int / int整数の割り算になり、小数部分は切り捨てられる
double result = total / people;代入先が double でも、右辺が int / int なら結果は 3.0
3.5 を得たい場合演算前に少なくとも一方を double 型にする
キャストの使い方(double)total / people のように演算前に使う

Javaの演算では、代入先の型だけでなく、演算に参加している値の型を見ることがとても大切です。

double result = total / people;

この式では、result が double 型でも、total / people が int 型どうしの演算なら、結果は整数になります。

double result = (double)total / people;

この式では、演算前に total を double 型にしているため、people も double 型にそろえられ、小数を含む結果になります。

型を意識して式を読む力がついてくると、Javaの計算結果を「なんとなく」ではなく、ルールに沿って正しく理解できるようになります。