web-dev-qa-db-ger.com

Berechnung der n-ten Wurzel in Java mit der Power-Methode

Ich habe versucht, ein kubisches Wurzelverzeichnis in Java mithilfe von Math.pow(n, 1.0/3) zu erhalten. Da es jedoch doppelte Werte teilt, wird die genaue Antwort nicht zurückgegeben. Bei 125 ergibt dies beispielsweise 4,9999999999. Gibt es eine Umgehung dafür? Ich weiß, dass es eine kubische Wurzelfunktion gibt, aber ich möchte diese korrigieren, damit ich höhere Wurzeln berechnen kann.

Ich möchte nicht abrunden, weil ich wissen möchte, ob eine Zahl eine Ganzzahl-Wurzel hat, indem Sie Folgendes tun: Math.pow(n, 1.0 / 3) % ((int) Math.pow(n, 1.0 / 3)).

13

Da mit double kein Kalkül mit beliebiger Genauigkeit möglich ist, haben Sie drei Möglichkeiten:

  1. Definieren Sie eine Genauigkeit, für die Sie entscheiden, ob ein double-Wert eine Ganzzahl ist oder nicht.
  2. Testen Sie, ob der gerundete Wert der double, die Sie verwenden, ein korrektes Ergebnis ist.
  3. Berechnen Sie ein Objekt BigDecimal , das Doppelwerte mit beliebiger Genauigkeit unterstützt.

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
}

Das Problem bei diesem Ansatz ist, wie "nah genug" definiert wird. Dies ist eine subjektive Frage und hängt von Ihren Anforderungen ab.

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;
}

Der Vorteil dieser Methode ist, dass keine Genauigkeit definiert werden muss. Wir müssen jedoch eine andere pow-Operation ausführen, damit dies die Leistung beeinträchtigt.

Option 3

Es gibt keine integrierte Methode zur Berechnung der doppelten Potenz eines BigDecimal. Diese Frage gibt dir einen Einblick, wie es geht.

6
Tunaki

Die Funktion Math.round wird auf den nächsten langen Wert gerundet, der in einem Double gespeichert werden kann. Sie können die beiden Ergebnisse vergleichen, um zu sehen, ob die Zahl eine kubische Ganzzahl hat.

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
}

Wenn das nicht ausreicht, können Sie versuchen, den Algorithmus this zu implementieren und frühzeitig zu stoppen, wenn das Ergebnis nicht als Ganzzahl erscheint.

5

Ich habe diese Methode zur Berechnung von floor(x^(1/n)) geschrieben, wobei x eine nicht negative BigInteger ist und n eine positive ganze Zahl ist. Es ist schon eine Weile her, also kann ich nicht erklären, warum es funktioniert, aber ich bin ziemlich zuversichtlich, dass ich mich beim Schreiben sehr gefreut habe, dass es garantiert schnell die richtige Antwort geben wird.

Um herauszufinden, ob x eine exakte n-th-Leistung ist, können Sie überprüfen, ob das Ergebnis, das durch die n-Potenz erhöht wird, Ihnen genau x zurückgibt.

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;
}

Um es zu benutzen:

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

Edit Nachdem ich die obigen Kommentare gelesen habe, kann ich mich daran erinnern, dass dies die Newton-Raphson-Methode für n-te Wurzeln ist. Die Newton-Raphson-Methode hat eine quadratische Konvergenz (was in der Alltagssprache bedeutet, dass sie schnell ist). Sie können es mit Zahlen versuchen, die Dutzende von Ziffern haben, und Sie sollten die Antwort in Sekundenbruchteilen erhalten. 

Sie können die Methode anpassen, um mit anderen Nummerntypen zu arbeiten, aber double und BigDecimal sind aus meiner Sicht für diese Art von Sache nicht geeignet.

1
Paul Boddington

Ich würde mich dafür entscheiden, meine eigene Funktion zu implementieren, möglicherweise basierend auf dieser Methode.

1
dimplex

Sie können einige Tricks verwenden, die aus dem Bereich der Mathematik stammen, um die Genauigkeit noch weiter zu verbessern

Überprüfen Sie die Implementierung hier: https://www.baeldung.com/Java-nth-root

0

Es ist ein ziemlich hässlicher Hack, aber Sie könnten einige von ihnen durch das Einrücken erreichen.

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

Das gibt Ihnen jeden dritten Würfel und jede zweite Wurzel.

0
John

Hier ist die Lösung, ohne Javas Math.pow-Funktion zu verwenden ..__ Sie erhalten fast die n-te Wurzel

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

Nun, dies ist eine gute Option, um sich in dieser Situation zu entscheiden ... Sie können sich darauf verlassen.

   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