web-dev-qa-db-ja.com

JavaでBigDecimalの分数パワーを実行するにはどうすればよいですか?

私の小さなプロジェクトでは、Math.pow(7777.66、5555.44)のようなことを非常に大きな数で行う必要があります。私はいくつかの解決策に出くわしました:

  • ダブルを使用します-しかし、数値が大きすぎます
  • BigDecimal.powを使用しますが、分数のサポートはありません
  • X ^(A + B)= X ^ A * X ^ B式(Bは2番目の数値の余り)を使用しますが、まだdoubleに変換するため、大きなXまたは大きなAはサポートされません。
  • ある種のテイラー級数アルゴリズムなどを使用します-私は数学があまり得意ではないので、解決策が見つからない場合はこれが最後のオプションです(一部のライブラリまたは(A + B)^(Cの式) + D))。

ライブラリや簡単な解決策を知っている人はいますか?多くの人が同じ問題に取り組んでいると思いました...

p.s.ほぼそれを行うと主張するApFloatというライブラリを見つけましたが、得られた結果は非常に近似的であったため、8 ^ 2でも60 ...

24
Eugene Marin

1.7976931348623157E308(Double.MAX_VALUE)での引数の解決策ですが、数百万桁の結果をサポートしています。

DoubleはMAX_VALUEまでの数値をサポートするため(たとえば、doubleの100!は9.332621544394415E157のようになります)、BigDecimal.doubleValue()を使用しても問題はありません。ただし、結果がMAX_VALUEよりも大きい場合は無限大になるため、Math.pow(double、double)を実行するだけではいけません。 SO:式X ^(A + B)= X ^ A * X ^ Bを使用して、計算をBigDecimal.powを使用するbigとMathを使用するsmall(2番目の引数の余り)の2乗に分割します。パウ、次に乗算します。 XはDOUBLEにコピーされます-MAX_VALUEより大きくないこと、AがINT(最大2147483647ですが、BigDecimal.powはとにかく10億を超える整数をサポートしていません)、Bは2倍、常に1未満であることを確認してください。このようにして、次のことができます(私のプライベート定数などは無視してください)。

    int signOf2 = n2.signum();
    try {
        // Perform X^(A+B)=X^A*X^B (B = remainder)
        double dn1 = n1.doubleValue();
        // Compare the same row of digits according to context
        if (!CalculatorUtils.isEqual(n1, dn1))
            throw new Exception(); // Cannot convert n1 to double
        n2 = n2.multiply(new BigDecimal(signOf2)); // n2 is now positive
        BigDecimal remainderOf2 = n2.remainder(BigDecimal.ONE);
        BigDecimal n2IntPart = n2.subtract(remainderOf2);
        // Calculate big part of the power using context -
        // bigger range and performance but lower accuracy
        BigDecimal intPow = n1.pow(n2IntPart.intValueExact(),
                CalculatorConstants.DEFAULT_CONTEXT);
        BigDecimal doublePow =
            new BigDecimal(Math.pow(dn1, remainderOf2.doubleValue()));
        result = intPow.multiply(doublePow);
    } catch (Exception e) {
        if (e instanceof CalculatorException)
            throw (CalculatorException) e;
        throw new CalculatorException(
            CalculatorConstants.Errors.UNSUPPORTED_NUMBER_ +
                "power!");
    }
    // Fix negative power
    if (signOf2 == -1)
        result = BigDecimal.ONE.divide(result, CalculatorConstants.BIG_SCALE,
                RoundingMode.HALF_UP);

結果の例:

50!^10! = 12.50911317862076252364259*10^233996181

50!^0.06 = 7395.788659356498101260513
25
Eugene Marin

big-math ライブラリはMITライセンスでリリースされ、ログ用の単純な静的ヘルパーBigDecimalMath.log(BigDecimal, MathContext)と、BigDecimalに含まれていない他の多くの関数があります。非常に単純です。使用するために、パフォーマンスを比較するためのベンチマークデータがたくさんあります。

0
Ben Holland

指数=対数。

見てください BigDecimalの対数

0
Matthew Flynn