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

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

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

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

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

24
задан Grodriguez 21 November 2010 в 11:58
поделиться

2 ответа

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

Так как double поддерживает числа до MAX_VALUE (например, 100! в double выглядит как это: 9.332621544394415E157), нет проблем с использованием BigDecimal.doubleValue(). Но вы не должны просто делать Math.pow(double, double), потому что, если результат больше, чем MAX_VALUE, вы просто получите бесконечность. ТАК: используйте формулу X ^ (A + B) = X ^ A * X ^ B, чтобы разделить вычисление на ДВЕ степени: большую, используя BigDecimal.pow, и маленькую (остаток второго аргумента), используя 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
25
ответ дан 29 November 2019 в 00:13
поделиться

Показатели = логарифмы.

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

0
ответ дан 29 November 2019 в 00:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: