生徒さんから質問があったので桁溢れ(オーバーフロー)について説明します。
きっかけは以下のプログラムです。
public class OverflowSample { public static void main(String[] args) { int i = 1; for (; i >= 0; i++) { } System.out.println(i); } }
こちらの実行結果はどうなるでしょう?
実は-2147483648と出力されます。
条件が0 >= iとなっているのにも関わらず、無限ループではなく実行できます。
しかも0からインクリメントしていたはずなのに何故かiがマイナスの値になってしまいました。
この原因が桁溢れ(オーバーフロー)です。
意味は名前の通り、決められたデータ型の範囲をオーバーしてしまうことです。
例えばintは-2147483648~2147483647の整数しか格納することはできません。
範囲外の値を代入しようとするとコンパイルエラーになります。
しかし、以下のコードはコンパイルが通ります。
int i = 2147483647 + 1;
そしてこのiを出力すると-2147483648が出力されます。
では何故マイナスの値になってしまうのでしょう?
これは細かい話になるのですが、数値が内部ではビットで扱われているからです。
byteで説明しましょう。
byteは8ビットです。つまり2進数で8桁というとです。
8つの0と1の組み合わせで-128~127の計256通りの数字が表現でき、以下の対応になっています。
-128を2進数にすると10000000
-1を2進数にすると11111111
0を2進数にすると00000000
127を2進数にすると01111111
では127、つまり01111111に1をプラスするとどうなるでしょう。
一番右のビットからどんどん繰り上がって、2進数の並びは10000000となります。
この10000000の並びはjavaのbyteでは-128にあたるわけです。
また、-1、つまり11111111に1プラスすると100000000になります。
byteは8ビットなので右8桁分しか認識しません。
したがって、一番左のビットが切り捨てられ00000000、つまり0になります。
要は127の次の数は最小の-128となってグルグル回るわけですね。
ちなみにbyteの場合は以下の記述はコンパイルエラーです。
byte b = 127 + 1;
もし上記を確認したいのであればキャストを利用しましょう。
System.out.println((byte) 128); // -128と出力される