2010-08-26 22 views
20

En mi pequeño proyecto, necesito hacer algo como Math.pow (7777.66, 5555.44) solo con MUY grandes números. Me encontré con algunas soluciones:¿Cómo hacer una potencia fraccionaria en BigDecimal en Java?

  • uso doble - pero los números son demasiado grandes
  • Uso BigDecimal.pow pero no hay soporte para fraccional
  • Utilice el X^(A + B) = x^A * X^B fórmula (B es el resto del segundo num), pero de nuevo no admite X grande o grande A porque todavía puedo convertir a doble
  • Use algún tipo de algoritmo de la serie Taylor o algo así - Estoy no es muy bueno en matemáticas, así que esta es mi última opción si no encuentro ninguna solución (algunas bibliotecas o una fórmula para (A + B)^(C + D)).

¿Alguien sabe de una biblioteca o una solución fácil? Pensé que muchas personas se enfrentan al mismo problema ...

p.s. Encontré una biblioteca llamada ApFloat que pretende hacerlo aproximadamente, pero los resultados que obtuve fueron tan aproximados que incluso 8^2 me dieron 60 ...

+0

Podría dar un ejemplo de lo que se intenta lograr, 8^2 = 64 sonidos pobre y 2^100^100 necesita ser reducido. – stacker

+0

Debo decir que probé el truco de la fórmula, ¡y hasta ahora funciona bien incluso con números con millones de dígitos! (Parece que no sé todo sobre double e int) ... Ejemplos: 50!^10! = 12.50911317862076252364259 * 10^233996181 50!^0.06 = 7395.788659356498101260513 El código es un poco largo para publicar aquí, pero se obtiene la idea de X^(A + B) = X^A * X^B ... Ahora Estoy tratando de entender cómo y por qué (y si) realmente funciona con números tan grandes. –

+0

Ya he dado la solución allí http://stackoverflow.com/questions/11848887/bigdecimal-to-the-power-of-bigdecimal-on-java-android/22556217#22556217 –

Respuesta

21

La solución para los argumentos bajo 1.7976931348623157E308 (Double.MAX_VALUE) pero los resultados de apoyo con millones de dígitos:

Puesto que los números dobles soporta hasta MAX_VALUE (por ejemplo, 100! en doble se ve así: 9.332621544394415E157), no hay ningún problema para utilizar BigDecimal.doubleValue(). Pero no deberías hacer Math.pow (doble, doble) porque si el resultado es mayor que MAX_VALUE obtendrás el infinito. SO: use la fórmula X^(A + B) = X^A * X^B para separar el cálculo en DOS potencias, la grande, usando BigDecimal.pow, y la pequeña (resto del 2 ° argumento), usando Math. pow, luego multiplicar X se copiará en DOBLE - asegúrese de que no sea más grande que MAX_VALUE, A será INT (máximo 2147483647 pero BigDecimal.pow no admite enteros más de mil millones de todos modos), y B será doble, siempre menos de 1. de esta manera usted puede hacer lo siguiente (caso omiso de mis constantes privadas, 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); 

Resultados ejemplos:

50!^10! = 12.50911317862076252364259*10^233996181 

50!^0.06 = 7395.788659356498101260513 
+2

Esto no es útil sin las clases 'CalculatorUtils',' CalculatorConstants' o 'CalculatorException' – Supuhstar

+0

Si el ejemplo no es útil, no lo use, es un ejemplo. Es por eso que escribí "ignorar mis constantes privadas". Puede adivinar o reemplazar cada uno de ellos de todos modos. –

0

Exponentes = logaritmos.

Tome un vistazo a Logarithm of a BigDecimal

+2

¿Eh? Ciertamente no son sinónimos si eso es lo que dices ... –

+0

El código fuente referido a la respuesta aceptada de esta pregunta tiene más soluciones que solo para el registro natural. – prunge

+1

@Prunge - Gracias. En realidad, nunca dije nada sobre el registro natural.Realmente, si miras la respuesta aceptada de Gene Marin, lo que él está describiendo es logarítmico. X^(A + B) = X^A * X^B es equivalente a decir log (base X) A + log (base X) B = log (base X) (A * B). Esto debería permitirle llevar los números a un orden de magnitud manejable. –

Cuestiones relacionadas