Comment faire une puissance fractionnaire sur BigDecimal en Java?

dans mon petit projet, je dois faire quelque chose comme les maths.pow (7777.66, 5555.44) seulement avec de très grands nombres. Je suis tombé sur quelques solutions:

  • utiliser le double-mais les nombres sont trop grands
  • Utilisez BigDecimal.pow mais pas de support pour les fractions
  • utilisez la formule X^(A+B)=X^A*X^B (B est le reste du second num), mais encore une fois aucun support pour big X ou big A parce que je continue à convertir en double
  • utilise une sorte d'algorithme de série Taylor ou quelque chose comme ça - Je ne suis pas très bon en maths donc celui-ci est ma dernière option si Je ne trouve pas de solutions (quelques bibliothèques ou une formule pour (A+B)^(C+D)).

qui 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 eu étaient si a peu près que même 8^2 m'en ont donné 60...

23
demandé sur Grodriguez 2010-08-27 01:43:11

2 réponses

la solution pour les arguments sous 1.7976931348623157E308 (Double.MAX_VALUE) mais des résultats à l'appui avec des MILLIONS de chiffres:

puisque double supporte les nombres jusqu'à MAX_VALUE (par exemple, 100! en double ressemble à ceci: 9.332621544494415E157), l'utilisation de BigDecimal ne pose aucun problème.doubleValue (). Mais tu ne devrais pas juste faire des maths.pow (double, double) parce que si le résultat est plus grand que MAX_VALUE vous obtiendrez juste l'infini. Ainsi: utiliser la formule X^(A+B)=X^A*X^B pour séparez le calcul en deux puissances, la grande, en utilisant BigDecimal.pow, et le petit (reste de la 2eme argument), l'utilisation des Mathématiques.pow, puis multiplier. X sera copié pour 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 plus d'un milliard de toute façon), et B sera double, toujours moins de 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
24
répondu Eugene Marin 2011-10-02 09:58:16

exposants = logarithmes.

regardez logarithme D'un BigDecimal

0
répondu Matthew Flynn 2017-05-23 12:09:17