見出し画像

初心者の時につまずいた除算の動作をJava言語仕様で確認


あいさつに代えて

7月末に福岡県に行ってきました。帰りに乗るはずだった飛行機が欠航になった為、代わりの飛行機に乗るまで半日時間が空くことになったので、JR博多シティにある映画館で過ごしました。
今回の画像は、映画館にある待合スペースの「トレインビュー」から撮影したものです。

Java言語仕様とは

Java言語仕様(The Java Language Specification)とは、その名の通りJava言語の言語仕様について記載されたものです。こちらのページに、JavaVM仕様(The Java Virtual Machine Specification)と共に、各バージョン毎に置かれています。
先日リリースされたバージョン23についても公開されていますが、今回の説明ではLTS版のバージョン21を使います。

Java言語仕様で動作を確認する

今回は、次の動作をJava言語仕様で確認したいと思います。

「整数同士を除算した結果は整数で戻る」

昔々、私がJavaで初めて本格的なプログラムを作成した際に、つまずいた動作がありました。それは、「整数同士を除算した結果は整数で戻る」事でした。
例えば、次の様な計算です。

int i = 22;
int j = 7;
double result1 = i / j; // JShellでの結果は3.0
double result2 = (double)i / j; // JShellでの結果は3.142857142857143

整数(intやlong)同士を除算した結果を小数点以下まで求めたい場合は、どちらかの値を実数(doubleやfloat)に変換する必要があるのですが、これにつまずきました。

除算演算子を確認

Java言語仕様では、除算演算子は「15.17.2. Division Operator /」に記載があります。この中で、「整数の除算は0に丸められる」(Integer division rounds toward 0.)とありますので、整数同士の除算した結果は整数になります。
あっさり確認は終わってしまいました、、、。

整数の除算となる条件を確認

ここでは少し掘り下げて、整数の除算となる条件を確認します。
乗算・除算・剰余の演算について、整数・浮動小数(実数)のどちらの演算が選ばれるかは「15.17. Multiplicative Operators」に記載があり、「the promoted type」(昇格された型)によって決定します。

  • 「the promoted type」がintかlongの場合、整数の演算

  • 「the promoted type」がfloatかdoubleの場合、浮動小数(実数)の演算

また、「the promoted type」の選び方は「5.6. Numeric Contexts」に記載があります。

  1. 「expression」(以降、値とします)が参照型の場合、プリミティブに変換(unboxing conversion)

  2. 次の条件により「the promoted type」を決定し、値を変換

    • いずれかの値がdoubleの場合、「the promoted type」はdoubleとし、doubleでない値をdoubleに変換

    • それ以外でいずれかの値がfloatの場合、「the promoted type」はfloatとし、floatでない値をfloatに変換

    • それ以外でいずれかの値がlongの場合、「the promoted type」はlongとし、longでない値をlongに変換

    • それ以外の場合、「the promoted type」はコンテキストの種類によって決定。乗算・除算・剰余の演算は「numeric arithmetic context」に当たる為、「the promoted type」はintとし、intでない値をintに変換

演算結果を確認

演算の結果については、演算の種類によって異なります。
整数の演算の場合、「4.2.2. Integer Operations」に記載があります。

  • いずれかの値がlongの場合、演算は64ビット精度で行い、結果はlongで返す

  • それ以外の場合、演算は32ビット精度で行い、結果はintで返す

浮動小数(実数)の演算の場合、「4.2.4. Floating-Point Operations」に記載があります。

  • いずれかの値がdoubleの場合、演算は64ビット浮動小数点演算で行い、結果はdoubleで返す

  • それ以外(でいずれかの値がfloat)の場合、演算は32ビット浮動小数点演算で行い、結果はfloatで返す

実際に計算して確認

ここまで調べた内容を確認する為に、実際に計算して確認したいと思います。JShellを使うと、簡単に結果を確認できます。
JShellの/openコマンドで指定するファイルは、次になります。

var nn1 = 22 / 7;
var nn2 = 22 / 7L;
var nn3 = 22 / 7f;
var nn4 = 22 / 7d;

var nn5 = 22L / 7;
var nn6 = 22L / 7L;
var nn7 = 22L / 7f;
var nn8 = 22L / 7d;

var nn9 = 22f / 7;
var nn10 = 22f / 7L;
var nn11 = 22f / 7f;
var nn12 = 22f / 7d;

var nn13 = 22d / 7;
var nn14 = 22d / 7L;
var nn15 = 22d / 7f;
var nn16 = 22d / 7d;

JShellの/varsコマンドで、実行結果を確認できます。

jshell> /vars
|    int nn1 = 3
|    long nn2 = 3
|    float nn3 = 3.142857
|    double nn4 = 3.142857142857143
|    long nn5 = 3
|    long nn6 = 3
|    float nn7 = 3.142857
|    double nn8 = 3.142857142857143
|    float nn9 = 3.142857
|    float nn10 = 3.142857
|    float nn11 = 3.142857
|    double nn12 = 3.142857142857143
|    double nn13 = 3.142857142857143
|    double nn14 = 3.142857142857143
|    double nn15 = 3.142857142857143
|    double nn16 = 3.142857142857143


いいなと思ったら応援しよう!