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

StackOverflow https://stackoverflow.com/questions/1657834

質問

2 つの数値を乗算するとオーバーフローが発生するという特殊なケースを処理したいと考えています。コードは次のようになります。

int a = 20;
long b = 30;

// if a or b are big enough, this result will silently overflow
long c = a * b;

それは簡易版です。実際のプログラムでは a そして b 実行時に他の場所から取得されます。私が達成したいのは次のようなものです:

long c;
if (a * b will overflow) {
    c = Long.MAX_VALUE;
} else {
    c = a * b;
}

これをどのようにコーディングするのが最適ですか?

アップデート: a そして b 私のシナリオでは常に負ではありません。

役に立ちましたか?

解決

のJava 8は、int型と長いためMath.multiplyExactMath.addExactなどがあります。これらは、オーバーフローのチェックを外すArithmeticExceptionをスローします。

他のヒント

abがある場合は、両方の正、あなたが使用することができます:

if (a != 0 && b > Long.MAX_VALUE / a) {
    // Overflow
}
あなたは正と負の両方の数に対処する必要がある場合は、

それはもっと複雑だ。

long maximum = Long.signum(a) == Long.signum(b) ? Long.MAX_VALUE : Long.MIN_VALUE;

if (a != 0 && (b > 0 && b > maximum / a ||
               b < 0 && b < maximum / a))
{
    // Overflow
}

ここで私はこれを確認するために手早く少しテーブルだ、そのオーバーフローをふりすることは-10または+10で起こるます:

a =  5   b =  2     2 >  10 /  5
a =  2   b =  5     5 >  10 /  2
a = -5   b =  2     2 > -10 / -5
a = -2   b =  5     5 > -10 / -2
a =  5   b = -2    -2 < -10 /  5
a =  2   b = -5    -5 < -10 /  2
a = -5   b = -2    -2 <  10 / -5
a = -2   b = -5    -5 <  10 / -2

長いオーバーフロー/アンダーフローをチェックし、安全な算術演算を提供するJavaライブラリがあります。例えば、グアバの<のhref =「https://google.github.io/guava/releases/snapshot-jre/api/docs/com/google/common/math/LongMath.html#checkedMultiply-long-long-」 abの積を返しのREL = "nofollowをnoreferrer"> LongMath.checkedMultiplyは(長い、長いb)は、それがオーバーフローしない、及びArithmeticException署名a * b演算でオーバフローlongをスロー設けられます。

あなたは(コードをテストしていない)代わりにjava.math.BigIntegerのを使用して、結果の大きさをチェックすることができます:

BigInteger bigC = BigInteger.valueOf(a) * multiply(BigInteger.valueOf(b));
if(bigC.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) {
  c = Long.MAX_VALUE;
} else {
  c = bigC.longValue()
}

、結果の大きさをチェックするために対数を使用します。

Javaはint.MaxValueのようなものを持っていますか? yesの場合は、してみてください。

if (b != 0 && Math.abs(a) > Math.abs(Long.MAX_VALUE / b))
{
 // it will overflow
}

編集:質問にはLong.MAX_VALUEを見て

ジュルビーから盗まれた

    long result = a * b;
    if (a != 0 && result / a != b) {
       // overflow
    }

アップデート:このコードは短く、うまく機能します。ただし、a = -1、b = Long.MIN_VALUE の場合は失敗します。

考えられる拡張機能の 1 つ:

long result = a * b;
if( (Math.signum(a) * Math.signum(b) != Math.signum(result)) || 
    (a != 0L && result / a != b)) {
    // overflow
}

これにより、除算なしで一部のオーバーフローが検出されることに注意してください。

ここで私は考えることができる最も簡単な方法です。

int a = 20;
long b = 30;
long c = a * b;

if(c / b == a) {
   // Everything fine.....no overflow
} else {
   // Overflow case, because in case of overflow "c/b" can't equal "a"
}

私は誰ものような解決策を見ていない理由はわからない。

if (Long.MAX_VALUE/a > b) {
     // overflows
} 

2つの数の大きくなるように選択します。

私はそれを直接編集して、それを交換することなく、ジョン・Kugelmanの答えに構築したいと思います。これは、理由は2の補数整数の場合ではないMIN_VALUE = -10の対称性、彼のテストケース(MAX_VALUE = 10MIN_VALUE == -MAX_VALUE)のために働きます。実際には、MIN_VALUE == -MAX_VALUE - 1ます。

scala> (java.lang.Integer.MIN_VALUE, java.lang.Integer.MAX_VALUE)
res0: (Int, Int) = (-2147483648,2147483647)

scala> (java.lang.Long.MIN_VALUE, java.lang.Long.MAX_VALUE)
res1: (Long, Long) = (-9223372036854775808,9223372036854775807)
MIN_VALUEMAX_VALUEに適用すると、

は、ジョンKugelmanの答えはa == -1とは何か(最初のカイルが提起した点)b ==オーバーフローケースを生成します。ここではそれを修正する方法があります:

long maximum = Long.signum(a) == Long.signum(b) ? Long.MAX_VALUE : Long.MIN_VALUE;

if ((a == -1 && b == Long.MIN_VALUE) ||
    (a != -1 && a != 0 && ((b > 0 && b > maximum / a) ||
                           (b < 0 && b < maximum / a))))
{
    // Overflow
}

これは、任意のMIN_VALUEMAX_VALUEのための一般的な解決策ではないのですが、それはJavaのLongIntegerabの任意の値のために一般的である。

多分:

if(b!= 0 && a * b / b != a) //overflow

この「解決策」についてはわかりません。

編集:b != 0 を追加しました。

反対票を投じる前に:a * b / b は最適化されません。これはコンパイラのバグでしょう。オーバーフローのバグをマスクできるケースはまだ見つかりません。

多分これはあなたを助けるます:

/**
 * @throws ArithmeticException on integer overflow
 */
static long multiply(long a, long b) {
    double c = (double) a * b;
    long d = a * b;

    if ((long) c != d) {
        throw new ArithmeticException("int overflow");
    } else {
        return d;
    }
}

指摘されているように、Java 8 には、オーバーフロー時に例外をスローする Math.xxxExact メソッドがあります。

プロジェクトに Java 8 を使用していない場合でも、非常にコンパクトな実装を「借用」できます。

ここでは、サードパーティ Web サイト上のこれらの実装へのリンクをいくつか示します。これらが有効であり続けるかどうかは保証されませんが、いずれにしても、JDK ソースにアクセスして、JDK ソース内でどのように魔法が行われるかを確認できるはずです。 java.lang.Math クラス。

Math.multiplyExact(long, long) http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/lang/Math.java?av=f#882

Math.addExact http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/lang/Math.java?av=f#805

などなど

C / C ++(ロング*ロング):

const int64_ w = (int64_) a * (int64_) b;    
if ((long) (w >> sizeof(long) * 8) != (long) w >> (sizeof(long) * 8 - 1))
    // overflow

のjava(int型* int型、申し訳ありません私はJavaでのint64見つけることができませんでした):

const long w = (long) a * (long) b;    
int bits = 32; // int is 32bits in java    
if ( (int) (w >> bits) != (int) (w >> (bits - 1))) {
   // overflow
}

大型タイプで結果1.save(int型* int型*長いint64型に入れ、長い、長いに結果を置く)

2.cmp結果>>ビットと結果>>(ビット - 1)

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top