プログラマの方は、演算時には、オーバーフローに関しては、
常に気を使っていると思いますが、
それでも忘れがちなケースを簡単にまとめます。
この記事は、以下の内容からピックアップした外伝的な内容です。
1. 話しを単純にするための前提条件
話しを単純にするために、32bitの符号付き整数型を想定します。
今回の内容に関しては、精度が決まっている符号付きの整数型であれば、
他のサイズでも該当するはずです。
Java, C#, C/C++では、
int、Int32, int32などを思いうかべると良いかと思います。
(C/C++では、int型が32ビットの処理系を想定。)
2. 乗算(掛け算)での忘れがちなオーバーフロー
大きな数値同士の掛け算とかは、オーバーフローしやすいのは、
すぐイメージできると思うので、本題ではありません。
本題としては、以下のようなケースです。
- C#
int a = Int32.MinValue;
int b = -1;
int answer = a * b;
- Java
int a = Integer.MIN_VALUE;
int b = -1;
int answer = a * b;
- C/C++
int a = INT_MIN;
int b = -1;
int answer = a * b;
a
には、-2147483648
が入っていますが、
-1
を掛けると、32ビットの符号付き整数で表現可能な2147483647
を超えます。
手元の環境では、いずれもanswer
変数の結果は、-2147483648
になりました。
C#に関しては、checked
にした場合は、OverFlowExceptionが発生します。
ビルドやコンパイル時点で、値が評価できる場合は、
その時点で、オーバーフローを検出する場合もあります。
3. 除算(割り算)での忘れがちなオーバーフロー
整数の割り算では、オーバーフローは発生しないと、
勘違いされているケースもありますが、ちゃんと(?!)オーバーフローする場合があります。
- C#
int a = Int32.MinValue;
int b = -1;
int answer = a / b;
- Java
int a = Integer.MIN_VALUE;
int b = -1;
int answer = a / b;
- C/C++
int a = INT_MIN;
int b = -1;
int answer = a / b;
掛け算の場合と同様ですが、
-1
で割ると、-1
を掛けるとの同じことなので、
32ビットの符号付き整数で表現可能な2147483647
を超えます。
手元の環境では、Javaでは、answer
変数の結果は、-2147483648
になりました。
C++では、整数オーバーフローの例外が発生しました。
C#に関しては、checked
かどうかにかかわらず、OverFlowExceptionが発生します。
3. まとめ
-
-1
を掛けると符号反転するとは限らない(オーバーフローするかもね)。 - 整数の割り算もオーバーフローする場合がある。
- 整数の割り算のオーバーフローの場合は、言語・環境でクセがある。