web-dev-qa-db-fra.com

Calcul de la nième racine en Java à l'aide de la méthode power

J'essayais d'obtenir une racine cubique en Java en utilisant Math.pow(n, 1.0/3), mais comme elle divise les doubles, elle ne renvoie pas la réponse exacte. Par exemple, avec 125, cela donne 4.9999999999. Y a-t-il une solution pour cela? Je sais qu’il existe une fonction racine cubique, mais j’aimerais y remédier afin de pouvoir calculer des racines plus hautes.

Je ne voudrais pas arrondir parce que je veux savoir si un nombre a une racine entière en faisant quelque chose comme ceci: Math.pow(n, 1.0 / 3) % ((int) Math.pow(n, 1.0 / 3)).

13
Sara Alaa Khodeir

Comme il n'est pas possible d'avoir un calcul de précision arbitraire avec double, vous avez trois choix:

  1. Définissez une précision pour laquelle vous décidez si une valeur double est un entier ou non.
  2. Testez si la valeur arrondie de la double que vous avez est un résultat correct.
  3. Effectuez un calcul sur un objet BigDecimal , qui prend en charge les valeurs doubles de précision arbitraire.

Option 1

private static boolean isNthRoot(int value, int n, double precision) {
    double a = Math.pow(value, 1.0 / n);
    return Math.abs(a - Math.round(a)) < precision; // if a and round(a) are "close enough" then we're good
}

Le problème avec cette approche est de savoir comment définir "assez proche". Ceci est une question subjective et dépend de vos besoins.

Option 2

private static boolean isNthRoot(int value, int n) {
    double a = Math.pow(value, 1.0 / n);
    return Math.pow(Math.round(a), n) == value;
}

L'avantage de cette méthode est qu'il n'est pas nécessaire de définir une précision. Cependant, nous devons effectuer une autre opération pow pour que cela affecte les performances.

Option 3

Il n'y a pas de méthode intégrée pour calculer la double puissance d'un BigDecimal. Cette question vous donnera un aperçu sur la façon de le faire.

6
Tunaki

La fonction Math.round arrondira à la valeur longue la plus proche pouvant être stockée dans un double. Vous pouvez comparer les 2 résultats pour voir si le nombre a une racine cubique entière.

double dres = Math.pow(125, 1.0 / 3.0);
double ires = Math.round(dres);
double diff = Math.abs(dres - ires);
if (diff < Math.ulp(10.0)) {
    // has cubic root
}

Si cela ne vous convient pas, vous pouvez essayer de mettre en œuvre this algorithme et vous arrêter plus tôt si le résultat ne semble pas être un entier.

5
Manos Nikolaidis

J'ai écrit cette méthode pour calculer floor(x^(1/n))x est un BigInteger non négatif et n est un entier positif. C'était il y a un certain temps, je ne peux donc pas expliquer pourquoi cela fonctionne, mais je suis assez convaincu que lorsque je l'ai écrit, j'étais heureux de pouvoir donner la bonne réponse assez rapidement.

Pour voir si x est une puissance n-th exacte, vous pouvez vérifier si le résultat élevé à la puissance n vous redonne exactement x.

public static BigInteger floorOfNthRoot(BigInteger x, int n) {
    int sign = x.signum();
    if (n <= 0 || (sign < 0))
        throw new IllegalArgumentException();
    if (sign == 0)
        return BigInteger.ZERO;
    if (n == 1)
        return x;
    BigInteger a;
    BigInteger bigN = BigInteger.valueOf(n);
    BigInteger bigNMinusOne = BigInteger.valueOf(n - 1);
    BigInteger b = BigInteger.ZERO.setBit(1 + x.bitLength() / n);
    do {
        a = b;
        b = a.multiply(bigNMinusOne).add(x.divide(a.pow(n - 1))).divide(bigN);
    } while (b.compareTo(a) == -1);
    return a;
}

Pour l'utiliser:

System.out.println(floorOfNthRoot(new BigInteger("125"), 3));

Edit Après avoir lu les commentaires ci-dessus, je rappelle maintenant qu’il s’agit de la méthode de Newton-Raphson pour les n-ième racines. La méthode Newton-Raphson a une convergence quadratique (ce qui veut dire que dans le langage courant, c'est rapide). Vous pouvez l'essayer sur des nombres comportant des dizaines de chiffres et vous devriez obtenir la réponse en une fraction de seconde. 

Vous pouvez adapter la méthode pour travailler avec d'autres types de nombres, mais double et BigDecimal ne sont, à mon avis, pas adaptés à ce type de chose.

1
Paul Boddington

J'irais pour implémenter ma propre fonction pour faire ceci, éventuellement basée sur this method.

1
dimplex

Vous pouvez utiliser certaines astuces issues du domaine des mathématiques, pour avoir une précision supérieure à celle-ci ... Comme celle-ci x ^ (1/n) = e ^ (lnx/n).

Vérifiez l’implémentation ici: https://www.baeldung.com/Java-nth-root

0

C'est un bidon plutôt laid, mais vous pouvez en atteindre quelques-uns en indentant.

System.out.println(Math.sqrt(Math.sqrt(256)));
    System.out.println(Math.pow(4, 4));
    System.out.println(Math.pow(4, 9));
    System.out.println(Math.cbrt(Math.cbrt(262144)));
Result:
4.0
256.0
262144.0 
4.0

Ce qui vous donnera chaque n ^ 3ème cube et toutes les n ^ 2 racines.

0
John

Voici la solution sans utiliser la fonction Math.pow de Java .

public class NthRoot {

public static void main(String[] args) {
    try (Scanner scanner = new Scanner(System.in)) {
        int testcases = scanner.nextInt();
        while (testcases-- > 0) {
            int root = scanner.nextInt();
            int number = scanner.nextInt();
            double rootValue = compute(number, root) * 1000.0 / 1000.0;
            System.out.println((int) rootValue);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private static double compute(int number, int root) {
    double xPre = Math.random() % 10;
    double error = 0.0000001;
    double delX = 2147483647;
    double current = 0.0;

    while (delX > error) {
        current = ((root - 1.0) * xPre + (double) number / Math.pow(xPre, root - 1)) / (double) root;
        delX = Math.abs(current - xPre);
        xPre = current;
    }
    return current;
}
0
Vpn_talent

Eh bien, c’est une bonne option à choisir dans cette situation . Vous pouvez compter sur ceci-

   System.out.println("     ");
   System.out.println("     Enter a base and then nth root");
   while(true)
   {
       a=Double.parseDouble(br.readLine());
       b=Double.parseDouble(br.readLine());
       double negodd=-(Math.pow((Math.abs(a)),(1.0/b)));
       double poseve=Math.pow(a,(1.0/b));
       double posodd=Math.pow(a,(1.0/b));
       if(a<0 && b%2==0)
       {
           String io="\u03AF";
           double negeve=Math.pow((Math.abs(a)),(1.0/b));
           System.out.println("     Root is imaginary and value= "+negeve+" "+io);
       }
       else if(a<0 && b%2==1)
       System.out.println("     Value= "+negodd);
       else if(a>0 && b%2==0)
       System.out.println("     Value= "+poseve);
       else if(a>0 && b%2==1)
       System.out.println("     Value= "+posodd);
       System.out.println("     ");
       System.out.print("     Enter '0' to come back or press any number to continue- ");
       con=Integer.parseInt(br.readLine());
       if(con==0)
       break;
       else
       {
           System.out.println("     Enter a base and then nth root");
           continue;
       }
    }
0
Avneesh Singh