Подтвердить что ты не робот

Как сделать дробную мощность на BigDecimal в Java?

В моем маленьком проекте мне нужно сделать что-то вроде Math.pow(7777.66, 5555.44) только с ОЧЕНЬ большими цифрами. Я наткнулся на несколько решений:

  • Используйте double - но цифры слишком большие.
  • Используйте BigDecimal.pow, но не поддерживайте дробное
  • Используйте формулу X ^ (A + B) = X ^ A * X ^ B (B - оставшаяся часть второго числа), но опять-таки нет поддержки большого X или большого A, потому что я все еще конвертирую в double
  • Используйте какой-то алгоритм серии Тейлора или что-то в этом роде - я не очень хорошо разбираюсь в математике, поэтому это мой последний вариант, если я не найду никаких решений (некоторые библиотеки или формула для (A + B) ^ (C + D)).

Кто-нибудь знает о библиотеке или простом решении? Я решил, что многие люди справляются с одной и той же проблемой...

p.s. Я нашел библиотеку под названием ApFloat, которая утверждает, что делает это примерно, но результаты, которые я получил, были настолько приблизительными, что даже 8 ^ 2 дали мне 60...

4b9b3361

Ответ 1

Решение для аргументов под 1.7976931348623157E308 (Double.MAX_VALUE), но поддерживающее результаты с МИЛЛИОНА цифр:

Так как double поддерживает номера до MAX_VALUE (например, 100! в двойном режиме выглядит так: 9.332621544394415E157), нет проблемы с использованием BigDecimal.doubleValue(). Но вы не должны просто делать Math.pow(double, double), потому что если результат больше MAX_VALUE, вы просто получите бесконечность. SO: используйте формулу X ^ (A + B) = X ^ A * X ^ B, чтобы отделить вычисление до TWO-мощностей, большую, используя BigDecimal.pow, и небольшую (остальную часть второго аргумента), используя Math. pow, затем умножьте. X будет скопирован в DOUBLE - убедитесь, что он не больше MAX_VALUE, A будет INT (максимум 2147483647, но BigDecimal.pow не поддерживает целые числа более миллиарда в любом случае), а B будет двойной, всегда меньше 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