Как сделать дробную мощность на BigDecimal в Java? - PullRequest
24 голосов
/ 27 августа 2010

В моем маленьком проекте мне нужно сделать что-то вроде 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 ...

Ответы [ 2 ]

24 голосов
/ 28 августа 2010

Решение для аргументов в 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, чтобы разделить вычисление на ДВУХ степеней, большое, используя BigDecimal.pow, и малое (остаток от 2-го аргумента), используя Math.пау, тогда умножь.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
0 голосов
/ 27 августа 2010

Экспоненты = логарифмы.

Взгляните на Логарифм большого десятичного числа

...