web-dev-qa-db-ja.com

Javaコードで整数オーバーフローを防ぐ方法は?

可能性のある複製:
Javaで2つの数値を乗算するとオーバーフローが発生するかどうか)を確認するにはどうすればよいですか?

Javaクラスメソッドがあり、*および+ オペレーション。

 int foo(int a、int b){
 ... // +と*を使用したいくつかの計算
} 

fooでオーバーフローが発生しないことを確認するにはどうすればよいですか?

BigDecimalを使用するか、すべての+と*を次のような「ラッパー」で置き換えることができると思います。

 int sum(int a、int b){
 int c = a + b; 
 if(a> 0 && b> 0 && c <0)
 throw new MyOverfowException(a、b)
 return c; 
} 
 
 int prod(int a、int b){
 int c = a * b; 
 if(a> 0 && b> 0 && c <0)
 throw new MyOverfowException(a、b)
 return c; 
 } 

Javaメソッドでintオーバーフローが発生しないことを確認するより良い方法はありますか?

30
Michael

工学的には難しい問題です。

Secure Coding サイトでは以下を推奨しています。

  • 前提条件の使用。つまり、入力を範囲チェックして、オーバーフローが不可能になるようにします。
  • 次に大きいプリミティブ整数型を使用して個々の算術演算を実行し、オーバーフローを明示的にチェックする、または
  • bigIntegerを使用します。

この Dr Dobbsの記事 は、明示的なオーバーフローチェックで各プリミティブ演算を行うプリミティブ算術メソッドのライブラリを作成することを提案しています。 (これを上記の箇条書き#2の実装と見なすことができます。)ただし、バイトコードの書き換えを使用して、算術バイトコードをオーバーフローチェックを組み込んだ同等のメソッドの呼び出しに置き換えることを推奨しています。

残念ながら、Javaでネイティブにオーバーフローチェックを有効にする方法はありません。 (しかし、同じことが他の多くの言語にも当てはまります;例えば、C、C++ ...)

20
Stephen C

オーバーフローをチェックする1つの方法は、オペランドを(元のオペランドビット長の2倍の)より大きな型に昇格させてから操作を実行し、結果の値が元の型に対して大きすぎるかどうかを確認することです。

int sum(int a, int b) {
    long r = (long)a + b;
    if (r >>> 32 != 0) {    // no sign extension
        throw new MyOverflowException(a, b);
    }
    return (int)r;
}

元の型がlongである場合、その大きな型としてBigIntegerを使用する必要があります。

23
Alnitak

合計:bが、intに格納できる最大値からaの値を引いた値の差よりも大きいかどうかを確認します。 aやbが負の値になる可能性がある場合は、(i)差分チェックでオーバーフローが発生しないように注意し、(ii)最小値について同様のチェックを実行する必要があります。

製品:それはもっと難しいです。整数を2つの半分の長さの整数に分割します(つまり、intが32ビットの場合、ビットマスキングとシフトを使用して2つの16ビット数に分割します)。次に、乗算を実行し、結果が32ビットに収まるかどうかを調べます。

一時的な結果のために単にlongを取得したくないという条件の下にあるすべてのもの。

6
JohnB

Aとbの両方が正または負であり、a + bの符号がaおよびbの符号と等しくない場合、オーバーフローが発生します。このルールを使用して、オーバーフローが発生して例外をスローするかどうかを判断できます。この期待をつかむと、以前の回答で述べた方法に従って対処できます。別の方法は、オーバーフローしない最大範囲型を使用して操作を行うことです。 Integer間の演算にはlongを使用できます。

3
Macok