解説
数学の数字とは違い、プログラミングで使う数値(整数)には、数を表現できる範囲が定められています。
たとえばJavaでは、以下のように変数の型によって、使用するビット数と扱える数字の範囲が決まっています(プログラミング言語やOSによって、ビット数が違うことがあります)。
変数の型 ビット数 扱える数字の範囲 2のn乗で表現
byte 8 -128~127 -2^7 ~2^7-1
short 16 -32768~32767 -2^15~2^15-1
int 32 -2147483648~2147483647 -2^31~2^31-1
long 64 -9223372036854775808 -2^63~2^63-1
~9223372036854775807
四則演算の結果などで、この範囲を超えた場合には、オーバーフローと言う現象が発生します。オーバーフローが発生すると、時計の針が12の次に1になるように、最小値にぐるりと値が移動します。
byteの場合で、どういったことが起きるのかを見てみましょう。
125 + 1 126 125 + 2 127 125 + 3 -128 ← 128は範囲から溢れるので、最小値の-128になる 125 + 4 -127 ← 129は範囲から溢れるので、最小値に1を足した-127になる 125 + 5 -126 ← 130は範囲から溢れるので、最小値に2を足した-126になる
このオーバーフローが起きると、プログラムが想定しない動作をする場合があります。
たとえばbyteの変数を1ずつ足していき、128以上になった場合に終了するプログラムを書いたとします。byteでは、127に1を足すと-128になるので、このプログラムは一生終わりません。
また、byteの変数で年齢を管理している場合は、128歳の年齢の人を登録しようとすると、-128歳になってしまいます。
変数の範囲には、気を付ける必要があります。
先程、byteの場合で、127から1増えた数字は-128になっていました。これは、2進数で、以下のように数字が表現されているからです。
126 → 0111 1110
127 → 0111 1111
-128 → 1000 0000
-127 → 1000 0001
^
このように、2進数の一番上のビットをプラスマイナスの符合として利用しているのです。こうしておくと、マイナス1から0になった場合にもコンピュータ内での処理が簡単になります。
-2 → 1111 1110
-1 → 1111 1111
0 → 0000 0000
1 → 0000 0001
^
なぜこのように01の値が変化するのかは、8桁目の上に、仮想の9桁目を考えると理解できます。
-2 → 0 1111 1110
-1 → 0 1111 1111
0 → 1 0000 0000
1 → 1 0000 0001
^
byteは8ビットまでしか扱えないので、9桁目は切り捨てられます。そのため、「1111 1111」に1を足すと「0000 0000」になります。「-1」に1を足すと「0」になるので、この方法で負の数字を表現すると大変便利です。
プログラムではこういった仕組みを利用して、最大桁数が1になった数字をマイナスとして扱うようにしています。
サンプル
オーバーフローを体験できる処理を、Javaで簡単に書いてみます。
byte b = 0;
System.out.println("byteのオーバーフロー\n");
for (int i = 0; i < 256; i ++) {
System.out.println(i + " : " + b);
b ++;
}
byteのオーバーフロー 0 : 0 1 : 1 2 : 2 ~~省略~~ 125 : 125 126 : 126 127 : 127 128 : -128 ←ここからオーバーフローが起きている 129 : -127 130 : -126 ~~省略~~ 253 : -3 254 : -2 255 : -1
