Cómo hacer un poder fraccionario en BigDecimal en Java?


En mi pequeño proyecto necesito hacer algo como matemáticas.pow (7777.66, 5555.44) solo con números MUY grandes. Me encontré con algunas soluciones:

  • Use double-pero los números son demasiado grandes
  • Utilice BigDecimal.pow pero sin soporte para fraccionario
  • Use la fórmula X^(A+B)=X^A*X^B (B es el resto del segundo número), pero de nuevo no hay soporte para big X o big A porque todavía convierto a double
  • 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 conoce una biblioteca o una solución fácil? Me imaginé que mucha gente lidia con el mismo problema...

P. S. Encontré una biblioteca llamada ApFloat que afirma hacerlo aproximadamente, pero los resultados que obtuve fueron tan aproximados que incluso 8^2 me dio 60...

Author: Grodriguez, 2010-08-27

2 answers

La solución para los argumentos bajo 1. 7976931348623157E308 (Doble.MAX_VALUE) pero apoyando resultados con MILLONES de dígitos:

Dado que double soporta números hasta MAX_VALUE (por ejemplo, ¡100! en double se ve así: 9. 332621544394415E157), no hay problema para usar BigDecimal.doubleValue(). Pero no deberías hacer matemáticas.pow (double, double) porque si el resultado es mayor que MAX_VALUE solo obtendrás infinito. Por lo tanto: utilice la fórmula X^(A + B) = X^A * X^B para separar la cálculo a DOS potencias, la grande, usando BigDecimal.pow, y el pequeño (resto del 2do argumento), usando Matemáticas.pow, luego multiplicar. X se copiará al DOBLE-asegúrese de que no es más grande que MAX_VALUE, A será INT (máximo 2147483647 pero el BigDecimal.pow no soporta enteros de más de mil millones de todos modos), y B será doble, siempre menos de 1. De esta manera puedes hacer lo siguiente (ignorar 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);

Ejemplos de resultados:

50!^10! = 12.50911317862076252364259*10^233996181

50!^0.06 = 7395.788659356498101260513
 24
Author: Eugene Marin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-02 09:58:16

Exponentes = logaritmos.

Echa un vistazo a Logaritmo de un BigDecimal

 0
Author: Matthew Flynn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:09:17