1

BigDecimal.pow(int i)非常に大きな基数と指数でを使用しようとしていますが、ArithmeticException: Underflowエラーが発生します。

簡単に言えば、コードは次のとおりです。

BigDecimal base = BigDecimal.valueOf(2147483645.4141948);
BigDecimal product = base.pow(987654321);

System.out.println("product = " + product.toPlainString());

はい、これは Project Euler の問題です。しかし、私は自分の数字が正しいことを知っています。これは数学の問題ではありませBigDecimal.pow(int i)ArithmeticException: Underflow.

が32ビットであることは知っていBigDecimalますが、これをバイパスしてそのような大きな値を計算する方法はありますか? それが役立つ場合は、下の 8 桁だけが必要なので、製品をフロアリングして改造する予定です。これを数学的に行う方法が他にある場合は、ヒントをお願いします。scaleint100000000

スタックトレース:

Exception in thread "main" java.lang.ArithmeticException: Underflow
    at java.math.BigDecimal.checkScale(BigDecimal.java:3841)
    at java.math.BigDecimal.pow(BigDecimal.java:2013)
    at test.main(test.java:10)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

Process finished with exit code 1

ありがとう。

4

2 に答える 2

1

答えは、「11234048」 (最後の 8 桁) で終わる 6913580247 の 10 進数です。基数には 7 つの小数があり、987654321 * 7 は 6913580247 に相当します。

BigDecimal私の問題は、この数値は 6913580247 のスケールが必要であり、そのスケールに使用する整数をオーバーフローするため、a で表すことができないことBigDecimalです。代わりに、どの形式の番号が必要かわかりません。次のコードは、結果を次のように出力します。

Result is 1.1234048e-6913580240

つまり、科学的表記法と同様に、科学的表記法の通常の範囲外の指数のみを使用します。私が使用しているモジュロ100000000の場合:

public static final BigDecimal moduloBase = new BigDecimal(10).pow(8); // 8 digits

今私がやります:

    long noOfDecimals = 987654321L * 7L;

    BigDecimal bd = new BigDecimal("54141948"); // last 8 digits of base
    bd = bd.pow(379721);
    bd = bd.remainder(moduloBase);
    bd = bd.pow(2601);
    bd = bd.remainder(moduloBase);

    double result = bd.doubleValue() / 10_000_000.0; // print with 7 decimals
    System.out.println("Result is " + result + "e" + (-(noOfDecimals - 7)));

Anton Dovzhenko's answer のトリックと、987654321 が 2601 * 379721 であるという事実を使用しています。私のコンピューターでは計算に約 4 秒かかりますが、これはおそらく大きく異なります。

フォローアップの質問をお待ちしております。

BigInteger編集: 計算の中心部分は、代わりにBigDecimal次のコードを使用して、より単純なコードとより高速に実行できます。

    BigInteger bi = new BigInteger("54141948");
    bi = bi.modPow(new BigInteger("987654321"), new BigInteger("100000000"));
    System.out.println("As BigInteger: " + bi);

11234048(現在、私たちが知っているように印刷されます。)

于 2017-01-09T07:57:26.137 に答える
1

計算は、いくつかの部分で壊れる可能性があります。次に例を示します。

BigDecimal base = BigDecimal.valueOf(2147483645.4141948);
base = base.setScale(20, BigDecimal.ROUND_FLOOR);
// 109739369 = 6455257 * 17
base = base.pow(17).setScale(20, BigDecimal.ROUND_FLOOR);
base = base.pow(6455257);

ArithmeticExceptionはセグメントscaleValue * powValue外であるため、スローされます。適用後にスケールを再設定する必要がある[Integer.MIN_VALUE; Integer.MAX_VALUE]ことに注意してください。これは、スケールが呼び出されるたびに再計算され、powBigDecimalpowoldScaleValue * powValue

また、電力値を取得するには時間がかかると思います

于 2016-12-24T04:53:44.583 に答える