2010-08-26 90 views
20

Dans mon petit projet, je dois faire quelque chose comme Math.pow (7777.66, 5555.44) seulement avec de très gros nombres. Je suis tombé sur quelques solutions:Comment faire une puissance fractionnaire sur BigDecimal en Java?

  • Utilisation double - mais les chiffres sont trop gros
  • Utilisez BigDecimal.pow mais pas de support pour fractionnelle
  • Utilisez le X^(A + B) = X^A * X^B formule (B est le reste de la deuxième num), mais de nouveau pas de support pour big X ou big A parce que je convertis toujours en double
  • Utilisez une sorte d'algorithme de la série Taylor ou quelque chose comme ça - Je suis pas très bon en maths donc celui-ci est ma dernière option si je ne trouve pas de solution (quelques librairies ou une formule pour (A + B)^(C + D)).

Quiconque connaît une bibliothèque ou une solution facile? J'ai pensé que beaucoup de gens traitent le même problème ...

p.s. J'ai trouvé une bibliothèque appelée ApFloat qui prétend le faire approximativement, mais les résultats que j'ai obtenus étaient si approximatifs que même 8^2 m'ont donné 60 ...

+0

Pourriez-vous donner un exemple de ce que vous essayez d'accomplir, 8^2 = 64 sons pauvre et 2^100^100 doit être réduit. – stacker

+0

Je dois dire que j'ai essayé l'astuce de la formule, et ça marche très bien jusqu'à présent, même avec des chiffres avec des millions de chiffres! (On dirait que je ne sais pas tout sur double et int) ... Exemples: 50!^10! = 12.50911317862076252364259 * 10^233996181 50!^0.06 = 7395.788659356498101260513 Le code est un peu long à poster ici, mais vous avez l'idée de X^(A + B) = X^A * X^B ... Maintenant J'essaie de comprendre comment et pourquoi (et si) cela fonctionne vraiment avec des chiffres aussi énormes. –

+0

J'ai déjà donné la solution là http://stackoverflow.com/questions/11848887/bigdecimal-to-the-power-of-bigdecimal-on-java-android/22556217#22556217 –

Répondre

21

La solution pour les arguments sous 1.7976931348623157E308 (Double.MAX_VALUE), mais les résultats de soutien avec des millions de chiffres:

Depuis le nombre de doubles supports jusqu'à MAX_VALUE (par exemple, 100! en double ressemble à ceci: 9.332621544394415E157), il n'y a pas de problème pour utiliser BigDecimal.doubleValue(). Mais vous ne devriez pas faire Math.pow (double, double) car si le résultat est supérieur à MAX_VALUE, vous obtiendrez simplement l'infini. SO: utilisez la formule X^(A + B) = X^A * X^B pour séparer le calcul de DEUX puissances, le grand, en utilisant BigDecimal.pow, et le petit (reste du second argument), en utilisant Math. pow, puis multipliez. X sera copié sur DOUBLE - assurez-vous qu'il n'est pas plus grand que MAX_VALUE, A sera INT (maximum 2147483647 mais le BigDecimal.pow ne supporte pas les entiers de plus d'un milliard de toute façon), et B sera double, toujours inférieur à 1. de cette façon, vous pouvez faire ce qui suit (ignorer mes constantes privées, etc.):

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); 

Résultats exemples:

50!^10! = 12.50911317862076252364259*10^233996181 

50!^0.06 = 7395.788659356498101260513 
+2

Ceci n'est pas utile sans les classes 'CalculatorUtils',' CalculatorConstants', ou 'CalculatorException' – Supuhstar

+0

Si l'exemple n'est pas utile, ne l'utilisez pas, c'est un exemple. C'est pourquoi j'ai écrit "ignore mes constantes privées". Vous pouvez deviner ou remplacer chacun d'entre eux de toute façon. –

0

Exponents = logarithmes.

Jetez un oeil à Logarithm of a BigDecimal

+2

Eh? Ils ne sont certainement pas synonymes si c'est ce que vous dites ... –

+0

Le code source référé à la réponse acceptée de cette question a plus de solutions que pour le journal naturel. – prunge

+1

@Prunge - Merci. Je n'ai jamais rien dit à propos de la bûche naturelle.Vraiment, si vous regardez la réponse acceptée de Gene Marin, ce qu'il décrit est logarithmique. X^(A + B) = X^A * X^B équivaut à dire log (base X) A + log (base X) B = log (base X) (A * B). Cela devrait vous permettre d'amener les nombres à un ordre de grandeur gérable. –