30

重複の可能性:
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)
     新しいMyOverfowException(a、b)をスローします
   cを返す;
}

int prod(int a、int b){
   int c = a * b;
   if(a> 0 && b> 0 && c <0)
     新しいMyOverfowException(a、b)をスローします
   cを返す;
}

intJavaメソッドでオーバーフローが発生し ないようにするためのより良い方法はありますか?

4

4 に答える 4

23

オーバーフローをチェックする 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

于 2012-09-01T09:41:41.830 に答える
20

工学的な観点からは難しい問題です。

Secure Codingサイトでは次のことを推奨しています。

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

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

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

于 2012-09-01T09:45:12.013 に答える
6

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

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

long一時的な結果として単純に取りたくないという条件の下のすべて。

于 2012-09-01T09:41:09.380 に答える
3

a と b の両方が正または負であると仮定し、a + b の符号が a および b の符号と等しくない場合、オーバーフローが発生します。このルールを使用して、オーバーフローが発生したかどうかを判断し、例外をスローできます。この例外をキャッチすると、以前の回答で言及されている方法に従って対処できます。別の方法は、オーバーフローしない最大の範囲型を使用して操作を行うことです。整数間の演算には long を使用できます。

于 2012-09-01T09:59:30.503 に答える