2010-08-26 1 views
20

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

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

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

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

+0

Не могли бы вы привести пример того, что вы пытаетесь достичь, 8^2 = 64 звуков бедные и 2^100^100 должны быть уменьшены. – stacker

+0

Должен сказать, я попробовал формулу трюков, и она отлично работает даже с числами с миллионами цифр! (Похоже, я не знаю всего о двойном и int) ... Примеры: 50!^10! = 12.50911317862076252364259 * 10^233996181 50!^0.06 = 7395.788659356498101260513 Код здесь немного длинный, но вы получаете идею X^(A + B) = X^A * X^B ... Теперь Я пытаюсь понять, как и почему (и если) он действительно работает с огромными числами. –

+0

Я уже дал решение там http://stackoverflow.com/questions/11848887/bigdecimal-to-the-power-of-bigdecimal-on-java-android/22556217#22556217 –

ответ

21

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

Поскольку номер двойными поддерживают до 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 
+2

Это не полезно без классов «CalculatorUtils», «CalculatorConstants» или «CalculatorException» – Supuhstar

+0

Если этот пример не полезен, не используйте его, это пример. Вот почему я написал «игнорировать мои личные константы». В любом случае вы можете угадать или заменить каждый из них. –

0

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

Посмотрите на Logarithm of a BigDecimal

+2

Э? Они, конечно, не синонимы, если это то, что вы говорите ... –

+0

Исходный код, отнесенный к принятому ответу на этот вопрос, имеет больше решений, чем только для естественного журнала. – prunge

+1

@Prunge - Спасибо. Я никогда ничего не говорил о естественном журнале.Действительно, если вы посмотрите на принятый ответ Джин Марин, то то, что он описывает, является логарифмическим. X^(A + B) = X^A * X^B эквивалентно тому, что log (основание X) A + log (база X) B = log (база X) (A * B). Это должно позволить вам привести числа к управляемому порядку величины. –