2

私の質問はこれに関連してい ますJavaで2つの数値を乗算するとオーバーフローが発生するかどうかを確認するにはどうすればよいですか?

私のアプリケーションでは、x と y はオンザフライで計算され、式のどこかで x と y を乗算する必要があります。

     int x=64371;
     int y=64635;

     System.out.println((x*y));

次のように間違った出力が得られます-134347711

上記の変数xyintを変更することlongで、上記のケースの正しい答えをすばやく修正できます。ただし、最大容量を超えて拡張されないという保証はxありません。ylong

質問

  1. 最終結果をどの変数にも格納していないのに、ここで負の数が得られるのはなぜですか? (好奇心のため

  2. x と y の値が事前にわからないため、このオーバーフローを回避するより迅速な方法はありますか。アプリケーションの実行全体に対して、すべての x と y を特定の大きな定数でlog除算するか、乗算する前に x と y を取得する必要がありますか? (実際の質問)

編集:

明確化

アプリケーションはビッグ データ セットで実行され、完了するまでに数時間かかります。遅すぎない解決策があるとよいでしょう。

最終結果は比較に使用されるため (元の結果にある程度比例する必要があるだけです)、パフォーマンスが大幅に向上する場合は、最終値に+-5% の誤差があっても許容されます。

4

6 に答える 6

6

数値が大きくなる可能性が高いことがわかっている場合は、BigInteger代わりに使用してください。intこれはオーバーフローしないことが保証されており、結果が大きすぎてまたはに収まらないかどうかを確認するか、値を直接long使用することができます。BigInteger

BigIntegerlongは任意精度のクラスであるため、直接のプリミティブ値(おそらくプロセッサ レジスタに格納できる) を使用するintよりも遅くなりますint。 )に収まり、ドメインで本当に必要かどうかlongを選択します。BigInteger

于 2013-10-17T18:52:49.873 に答える
5
  1. 整数オーバーフローのために負の数が得られます。2 の補数表現を使用すると、Java は最上位ビット1が負に設定された整数を解釈します。
  2. 加算または減算によってオーバーフローまたはアンダーフローが発生する状況を検出するために、ビット操作を含む非常に巧妙な方法があります。結果がどのくらい大きくなるかわからない場合は、 に切り替えることをお勧めしますBigInteger。ただし、Java には、オブジェクトに対する数学演算BigIntegerを見慣れたものにする演算子のオーバーロード機能がないため、コードは非常に異なって見えます。コードも多少遅くなります。ただし、オーバーフローとアンダーフローに対しては保証されます。

編集 :

パフォーマンスが大幅に向上する場合は、最終値に +-5% の誤差があっても問題ありません。

+-5% の誤差は誤差の大きな許容範囲です! これが実際にシステムで受け入れられる場合は、doubleorを使用するよりも機能する可能性がありますfloat。これらの型は不正確ですが、その範囲は の範囲よりもはるかに大きく、int簡単にはオーバーフローしません。ただし、浮動小数点データ型は本質的に不正確であるため、細心の注意を払う必要があります。一般的な精度の問題を回避するために、データの表現方法に常に留意する必要があります。

于 2013-10-17T18:54:52.357 に答える
1

最終結果を変数に保存していないのに、ここで負の数が得られるのはなぜですか? (好奇心のため)

x と y は int 型です。それらを乗算すると、それらは一時的にメモリに入れられます。そのタイプは、オリジナルのタイプによって決まります。int*int は常に int を生成します。溢れても。それらの 1 つを long にキャストすると、乗算のために long が作成され、オーバーフローは発生しません。

x と y の値がわからないので、このオーバーフローを回避するより簡単な方法はありますか。おそらく、アプリケーションの実行全体に対してすべての x と y を特定の大きな定数で除算するか、x と y を乗算する前に対数を取る必要がありますか? (実際の質問)

x と y が正の場合、確認できます

if(x*y<0)
{
    //overflow
}
else
{
    //do something with x*y
}

残念ながら、これは絶対確実ではありません。再び正の数にオーバーランする可能性があります。例: System.out.println(Integer.MAX_VALUE * 3);2147483645 が出力されます。

ただし、この手法は常に 2 つの整数を加算する場合に有効です。

他の人が言ったように、BigInteger はオーバーフローしないはずです。

于 2013-10-17T18:57:32.943 に答える
0

負の値は (64371 * 64635) - 2^32 です。Java は、実行時に拡張プリミティブ変換を実行しません。

于 2013-10-17T18:56:42.623 に答える
0

int の乗算は、変数に格納されていなくても、常に int になります。あなたの製品は4160619585で、これには符号なし32ビット(Javaにはありません)、またはより大きなワードサイズ(または誰かがすでに述べたようにBigInteger)が必要です。

代わりにログを追加することもできますが、結果を指数化しようとすると、符号付き 32 ビットに正しく丸められない数値が得られます。

于 2013-10-17T18:57:05.057 に答える