2010-08-26 9 views
20

Nel mio piccolo progetto ho bisogno di fare qualcosa come Math.pow (7777.66, 5555.44) solo con MOLTO grandi numeri. Mi sono imbattuto in alcune soluzioni:Come fare una potenza frazionale su BigDecimal in Java?

  • Uso doppia - ma i numeri sono troppo grandi
  • Usa BigDecimal.pow ma nessun supporto per frazionaria
  • Utilizzare la X^(A + B) = X^A * X^B formula (B è il resto del secondo numero), ma ancora nessun supporto per X grande o A grande perché converto ancora in doppio
  • Usa qualche tipo di algoritmo della serie Taylor o qualcosa del genere - Sono non molto bravo in matematica quindi questa è la mia ultima opzione se non trovo alcuna soluzione (alcune librerie o una formula per (A + B)^(C + D)).

Qualcuno sa di una biblioteca o di una soluzione facile? Ho pensato che molte persone affrontano lo stesso problema ...

p.s. Ho trovato una libreria chiamata ApFloat che afferma di farlo approssimativamente, ma i risultati che ho ottenuto erano così approssimativi che anche 8^2 mi ha dato 60 ...

+0

può fare un esempio di ciò che si tenta di realizzare, 8^2 = 64 suoni povero e 2^100^100 deve essere ridimensionato. – stacker

+0

Devo dire che ho provato il trucco della formula, e funziona fino ad ora anche con numeri con milioni di cifre! (Sembra che io non sappia tutto su double e int) ... Esempi: 50!^10! = 12.50911317862076252364259 * 10^233996181 50!^0.06 = 7395.788659356498101260513 Il codice è un po 'lungo da postare qui, ma si ha l'idea di X^(A + B) = X^A * X^B ... Ora Sto cercando di capire come e perché (e se) funziona davvero con numeri enormi. –

+0

Ho già dato la soluzione lì http://stackoverflow.com/questions/11848887/bigdecimal-to-the-power-of-bigdecimal-on-java-android/22556217#22556217 –

risposta

21

La soluzione per gli argomenti sotto 1.7976931348623157E308 (Double.MAX_VALUE), ma i risultati che sostengono con milioni di cifre:

Dato che i numeri doppi supporta fino a MAX_VALUE (ad esempio, 100! in double appare così: 9.332621544394415E157), non c'è alcun problema nell'usare BigDecimal.doubleValue(). Ma non dovresti semplicemente eseguire Math.pow (double, double) perché se il risultato è maggiore di MAX_VALUE otterrai solo l'infinito. SO: usa la formula X^(A + B) = X^A * X^B per separare il calcolo in DUE poteri, il grande, usando BigDecimal.pow, e il piccolo (resto del secondo argomento), usando Math. pow, quindi moltiplicare. X verrà copiato in DOUBLE - assicurati che non sia più grande di MAX_VALUE, A sarà INT (massimo 2147483647 ma BigDecimal.pow non supporta integer più di un miliardo in ogni caso), e B sarà doppio, sempre meno di 1. in questo modo è possibile effettuare le seguenti (ignorare i miei costanti privati ​​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); 

Risultati esempi:

50!^10! = 12.50911317862076252364259*10^233996181 

50!^0.06 = 7395.788659356498101260513 
+2

Questo non è utile senza le classi 'CalculatorUtils',' CalculatorConstants' o 'CalculatorException' – Supuhstar

+0

Se l'esempio non è utile non usarlo, è un esempio. Questo è il motivo per cui ho scritto "ignora le mie costanti private". Puoi indovinare o sostituire ognuno di loro comunque. –

0

Esponenti = logaritmi.

Date un'occhiata a Logarithm of a BigDecimal

+2

Eh? Non sono certamente sinonimi se questo è quello che stai dicendo ... –

+0

Il codice sorgente riferito alla risposta accettata di questa domanda ha più soluzioni del solo log naturale. – prunge

+1

@Prunge - Grazie. Non ho mai detto nulla sul registro naturale.Davvero, se guardi la risposta accettata di Gene Marin, quello che sta descrivendo è logaritmico. X^(A + B) = X^A * X^B equivale a dire log (base X) A + log (base X) B = log (base X) (A * B). Questo dovrebbe consentire di portare i numeri a un ordine di grandezza gestibile. –