Wurzelberechnung (mittels Newton)

  • Themenstarter Themenstarter java-fee
  • Beginndatum Beginndatum
J

java-fee

Gast
Hallo zusammen,

ich arbeite z.Zt. an einem Programm zur Wurzelberechnung. Dabei soll eine Klasse für die berechnungsschritte herhalten. Da ich mit der Umsetzung von Mathematischen Formeln in java etwas auf kriegsfuss stehe, komme ich auch nicht weiter als wie unten zu sehen...

Der Startwertsoll x/10 liefern, computeRoot stellt die Wurzelberechnungsfunktion dar (ich hoffe, die stimmt...?), und der Approximationsschritt macht mir die meisten sorgen. Irgendwie habe ich da auch den Überblick verloren, wäre schön, wenn mir einer da mal auf die Sprünge helfen könnte, wie diese approximierung am besten darstellbar ist. Ausserdem wollte ich noch eine Schleife integrieren, die nach einer best. Anzahl von Schritten abbricht. isCloseEnough prüft, ob die Punkte ausreichend nah genug beieinander sind, ich hoffe das habe ich richtig umgesetzt.

Zuletzt möchte ich den Funktionsaufruf mittels zweier Eingabefenster realisieren, (das schreibe ich gerade), das man per button click die 4. Wurzel aus der Zahl 100 berechnet. Aber das nur am Rande, was noch fehlt.

Kann mir jemand bei der approximierung weiterhelfen?

Java:
public class New {

	public static void main(String[] args) {


	}

    class NewtonRoot {

    	static double computeRoot int n, double x) {
    		return x - (x - n /(x * x)) / 3;
    	}

    	static double getStartValue (double x) {
    		return x / 10;
    	}

    	static double doApproximationStep (int n, double x, double y) {
    		int n = 1;
    		double h = y - x;
    		double y0 = f.apply (x);
    		double yn = f.apply (y);
    		double y = h - x (yo + yn);
    		double yalt;
    		do {
    			yalt = y;
    			h = h / 2;
    			y = h * (y0 + yn) / 2 + h * summe (n, h, f, a)
    		} while (! isCloseEnough (y, yalt));
    		return y;
    	}

    	static boolean isCloseEnough (double x1, double x2) {
    		return Math.abs (x1 - x2) < 1E - 10;
    	}


    }




}
 
Kann mir jemand bei der approximierung weiterhelfen?

Kannst Du vielleicht einmal die mathematische Formel posten, die Du zu implementieren versuchst? Das was ich unter dem Newtonschen Verfahren verstehe, findest Du z.B. hier:

Newton-Verfahren ? Wikipedia

und das finde ich in Deinem Code so irgendwie nicht wieder. Ich vermute mal, Deine computeRoot() Methode müsste so aussehen

Code:
static double computeRoot(double a, double x){
  return (x + a / x) * 0.5;
}

Was in der doApproximationStep() Methode passieren soll, ist mir unklar. Was für Werte übergibst Du da? Was ist "f" für ein Objekt? Außerdem deklarierst Du übergebene Variablen neu (z.B. n), das geht so nicht. Was ist "summe()" für eine Methode? Eine selbst geschriebene? Wo ist die....

ME müsste dein Programm ungefähr so aussehen:

Code:
public double static calcRoot(double val){
     double x = getStartValue(val);
     double xAlt;
     do {
           xAlt = x;
           x = computeRoot(val, x);
     } while (!isCloseEnough(x, xAlt));
    return x;
}

Und bei isCloseEnough ist Dein return Ausdruck nicht ok. Bei Java findest Du die mathematischen Dinge in Math, also auch

Code:
Math.exp(-10);
 
Ich sitz gerade an einer ähnlichen Aufgabe, da würde mir sehr helfen, die hier zur Übung fertig zu programmieren.
Die Hilfsfunktion doApproximatonStep implementiert glaub ich einen Approximationsschritt ( berechnet also den nächsten Näherungswert). Sogesehen müsste Sie ja jeweils als Parameter n, x und immer zuvor berechneten Näherungswert y haben.
Genau das interessiert mich, weil man damit jeweils die einzelnen Schritte zur nten Wurzelberechnung ausgeben könnte.
Kann da vielleicht jemand mit der Programmierung unter die Arme greifen?
 
Die Hilfsfunktion doApproximatonStep implementiert glaub ich einen Approximationsschritt ( berechnet also den nächsten Näherungswert). Sogesehen müsste Sie ja jeweils als Parameter n, x und immer zuvor berechneten Näherungswert y haben.

Ich mag auf meiner Leitung stehen, aber genau das passiert doch in meinem Lösungsvorschlag in der do...while Schleife, oder? Das "n" braucht man m.E. für die Berechnung nicht (wird ja auch in der Methode des TO nicht verwendet, nur n der etwas unklaren Methode "summe"). Wenn Du es also Info haben willst, dann lass doch einfach einen Zähler mitlaufen.
 
Hallo,

also erstmal sorry, hatte da eine frühere Version gepostet, unten die aktuelle, mit den Eingaben.

Die Do-Schleife mit der Methode isCloseEnough habe ich so aus den Unterlagen übernommen, ich bin davon ausgegangen dass das stimmt und so verwendet werden kann (natürlich mit den richtigen Variablen).

Was eigentlich passieren soll. mittels des NEwton-Verfahrens soll eine Wurzel n aus einer Zahl x gezogen werden. Die Klasse NewtonRoot soll 4 Methoden beinhalten:

computeRoot - Wurzelberechnungsfunktion mit n und x
getStartValue - liefert für x den startwert x/10 zurück
doApproximationStep - berechnet den Näherungswert (neben x und n ist y der Näherungswert aus dem vorherigen schritt)
isCloseEnough - ergibt true, wenn x1 und x2 nahe genug beieinander liegen (also bis 10^10)

Wenn man zB die 3.W. aus 10 berechnen möchte soll folgender Ausgabe kommen:

1. Schritt: 1
2. Schritt: 4
3. Schritt: 2.8750000000000004
4. Schritt: 2.3199432892249527
5. Schritt: 2.165961555177793
6. Schritt: 2.1544959251533746
7. Schritt: 2.154434691772293
8. Schritt: 2.1544346900318834


Java:
public class New {

	public static void main(String[] argv) throws IOException {

		// Werte eingeben
        Scanner in = new Scanner( System.in);

        System.out.println("Geben sie die Zahl ein, aus der die Wurzel gezogen werden soll! "); // Anfangswert eingeben
        String zahl = in.nextLine();
        try {
            Anfangswert = Double.parseDouble(zahl);
            }
        catch (Exception e) {
            System.out.println("Keine gültige Eingabe!");
            }


        System.out.println("Geben sie die Wurzel ein, die berechnet werden soll!"); // Nutzungsdauer eingeben
        String wurzel = in.nextLine();
        try {
            Nutzungsdauer = Integer.parseInt(wurzel);
            }
        catch (Exception e) {
            System.out.println("Keine gültige Eingabe!");
            }
        // Verarbeitung
        double r = newtonRoot.computeRoot(n, x);


        // Ausgabe
        System.out.println ("1.Schritt"+ r +);

	}

    class NewtonRoot {

    	static double computeRoot int n, double x) {
    		return x - (x - n /(x * x)) / 3;
    	}

    	static double getStartValue (double x) {
    		return x / 10;
    	}

    	static double doApproximationStep (int n, double x, double y) {
    		int n = 1;
    		double h = y - x;
    		double y0 = f.apply (x);
    		double yn = f.apply (y);
    		double y = h - x (yo + yn);
    		double yalt;
    		do {
    			yalt = y;
    			h = h / 2;
    			y = h * (y0 + yn) / 2 + h * summe (n, h, f, a)
    		} while (! isCloseEnough (y, yalt));
    		return y;
    	}

    	static boolean isCloseEnough (double x1, double x2) {
    		return Math.abs (x1 - x2) < 1E - 10;
    	}


    }




}

...Verarbeitung und Ausgabe ist natürlich nicht richtig, ich überlege wie ich das elegant lösen kann. Im idealfall rufe ich ja eine Funktion auf, die alle Methoden der Klasse newtonRoot durchläuft und dann eben nach einer festgelegten Anzahl von Schritten (8 wie oben vielleicht nicht, eher 10 oder 100) die ausgabe abbricht...
 
Ok, aber irgendwie sollte das Programm vielleicht erst mal grundsätzlich laufen. Folgende Fehler sehe ich auf den ersten Blick:

1. Jede Variable muss deklariert sein. Anfangswert und Nutzungsdauer sind es nicht. Auch n und x, die Du computeRoot() übergibst, sind werder deklariert noch ist Ihnen ein Wert zugewiesen
2. Wenn Du eine innere Klasse mit statistischen Methoden erzeugen willst, muss auch die innere Klasse statisch sein (also static class NewtonRoot)
3. Wenn Du eine statische Methode aufrufst, dann musst Du den Klassennahmen verwenden, also NewtonRoot.computeRoot() und nicht newtonRoot.computeRoot()
4. Bei Deiner System.out.println() Methode ist hinten ein "+" zuviel
5. doApproximationStep() ist mir immer noch ein Rätsel: Du übergibst n, x und y und deklarierst die Werte dann neu, das geht nicht. Und was sind "f" und "summe"?
 
Umgesetzt müsste das ja so aussehen:

public class Newton {


public static void main(String[] args) {


System.out.println(calcRoot(10));




}

static double computeRoot(double n, double x){

return (x + n / x) * 0.5;
}

static double getStartValue (double x) {
return x / 10;
}


static boolean isCloseEnough (double x1, double x2) {
return Math.abs (x1 - x2) < Math.exp(-10);
}


public static double calcRoot(double val){
double x = getStartValue(val);
double xAlt;
do {
xAlt = x;
x = computeRoot(val, x);
System.out.println(x);
} while (!isCloseEnough(x, xAlt));
return x;
}



}




Bei mir will der aber nicht ausspucken, was ausgespuckt werden soll. Ideen?
 
Ach sorry, hab da wieder eine falsche version reingestellt...habs soeben korrigiert.

1. Anf. und nutzungsdauer ist natürlich quark, hab die eingabe per copy&paste aus einem alten prog übernommen, das sind dann x (double) und n(int), also die zahl und die gewünschte wurzel.

2. Das mit der klasse ist klar, ist schon korrigiert.

3. auch klar, schreibfehler.

4. hatte es schon bemerkt. Wie gesagt ist die Verarbeitung und ausgabe noch eher platzhalter, ich möchte das so relisieren, dass es beim Aufruf alle Methoden durchläuft (oder macht sie das automatisch, wenn ich die Klasse aufrufe? Ich denke momentan wird nur die Methode computeRoot abgearbeitet, oder?) und dass dann jeweils die einzelnen Schritte ausgegeben werden, bis die in der schleife (die noch zu integrieren ist - oder kann ich das schon in der Klasse NewtonRoot festlegen?) festgelegte Anzahl an schritten erreicht ist.

5. genau Das ist auch mein Problem. ich weiss nicht wie ich den Näherungswert in Java umsetzte, so ähnlich habe ich es aus einem anderen prog übernommen, ich lese mich da grad ein, bin über jeden Hinweis dankbar. X und N werden übernommen, und dann ein Näherungswert berechnet... Y ist der vorherige Näherungswert (welche nehme ich da zum Anfang?)

Ausserdem grüble ich noch, wozu die methode getstartValue dient.Ich kann doch auch direkt mit x losrechen, oder soll x/10 der erste angenommene Näherungswert sein?

Ich stell mich da etwas doof an, mathe in java umzusetzen ist nicht grad mein "Steckenpferd" ums mal dezent auszudrücken...Hoffe daher, jemand kann mir weiterhelfen....🙁
 
...kann meine Post leider nicht editieren, hier nochmal:

Java:
public class New {

	public static void main(String[] argv) throws IOException {

		// Werte eingeben
        Scanner in = new Scanner( System.in);

        System.out.println("Geben sie die Zahl ein, aus der die Wurzel gezogen werden soll! "); // Zahl eingeben
        String zahl = in.nextLine();
        try {
            x = Double.parseDouble(zahl);
            }
        catch (Exception e) {
            System.out.println("Keine gültige Eingabe!");
            }


        System.out.println("Geben sie die Wurzel ein, die berechnet werden soll!"); // Wurzel eingeben
        String wurzel = in.nextLine();
        try {
            n = Integer.parseInt(wurzel);
            }
        catch (Exception e) {
            System.out.println("Keine gültige Eingabe!");
            }


		// Verarbeitung
        double r = NewtonRoot.computeRoot(n, x);


        // Ausgabe
        System.out.println ("1.Schritt"+ r);


	}

    static class NewtonRoot {

    	static double computeRoot (int n, double x) {
    		return x - (x - n /(x * x)) / 3;
    	}

    	static double getStartValue (double x) {
    		return x / 10;
    	}

    	static double doApproximationStep (int n, double x, double y) {
    		int n = 1;
    		double h = y - x;
    		double y0 = f.apply (x);
    		double yn = f.apply (y);
    		double y = h - x (yo + yn);
    		double yalt;
    		do {
    			yalt = y;
    			h = h / 2;
    			y = h * (y0 + yn) / 2 + h * computeRoot (n, x);
    		} while (! isCloseEnough (y, yalt));
    		return y;
    	}

    	static boolean isCloseEnough (double x1, double x2) {
    		return Math.abs (x1 - x2) < 1E - 10;
    	}


    }

}

@hungrig: schreib das mal mit JAVA-tags, das liest sich besser.
 
Java:
public class New {

	public static void main(String[] argv) {

		// Variablendeklarationen
		double x;
		int n;


		// Werte eingeben
        Scanner in = new Scanner( System.in);

        System.out.println("Geben sie die Zahl ein, aus der die Wurzel gezogen werden soll! "); // Zahl eingeben
        String zahl = in.nextLine();
        try {
            x = Double.parseDouble(zahl);
            }
        catch (Exception e) {
            System.out.println("Keine gültige Eingabe!");
            }


        System.out.println("Geben sie die Wurzel ein, die berechnet werden soll!"); // Wurzel eingeben
        String wurzel = in.nextLine();
        try {
            n = Integer.parseInt(wurzel);
            }
        catch (Exception e) {
            System.out.println("Keine gültige Eingabe!");
            }


		// Verarbeitung
		double r = NewtonRoot.computeRoot(n, x);


        // Ausgabe
        System.out.println(+ r(10));

	}

    static class NewtonRoot {

    	static double computeRoot (int n, double x) {
    		return x - (x - n /(x * x)) / 3;
    	}

    	static double getStartValue (double x) {
    		double y = x / 10;
    		return y;
    	}

    	/**static double doApproximationStep (int n, double x, double y) {
    		int n = 1;
    		double h = y - x;
    		double y0 = f.apply (x);
    		double yn = f.apply (y);
    		double y = h - x (yo + yn);
    		double yalt;
    		do {
    			yalt = y;
    			h = h / 2;
    			y = h * (y0 + yn) / 2 + h * computeRoot (n, x);
    		} while (! isCloseEnough (y, yalt));
    		return y;
    	}**/

		static double doApproximationStep(int n, double x, double y){
            x = getStartValue(x);
            double xAlt;
            do {
               xAlt = x;
               x = computeRoot(x, y);
               System.out.println(x);
            } while (!isCloseEnough(x, xAlt));
            return x;
        }

    	static boolean isCloseEnough (double x1, double x2) {
    		return Math.abs (x1 - x2) < Math.exp(-10);
    	}


    }

}

...das ist der momentane stand, es hakt noch bei Verarbeitung/ausgabe sowie der Approximation (fehler mit den arten der Variable, int und double, was auf mein Problem zurückführt, dass ich den Ablauf der approximation immer noch nicht durchschaue...)

Weiss da jemand Rat? Vielen Dank im voraus! 🙂
 
So, ich habe mir diese Newtonsche Näherungsformel für alle Wurzeln noch einmal angeschaut und Deinen Code darauf hin geändert. Der folgende Code macht m.E. genau das, was er soll:

Code:
public class New {
 
    public static void main(String[] argv) throws IOException {
 
        // Werte eingeben
        Scanner in = new Scanner( System.in);
 
        System.out.println("Geben sie die Zahl ein, aus der die Wurzel gezogen werden soll! "); // Zahl eingeben
        String zahl = in.nextLine();
        double a = 0.0;
        try {
            a = Double.parseDouble(zahl);
            }
        catch (Exception e) {
            System.out.println("Keine gültige Eingabe!");
            }
 
 
        System.out.println("Geben sie die Wurzel ein, die berechnet werden soll!"); // Wurzel eingeben
        String wurzel = in.nextLine();
        int n = 1;
        try {
            n = Integer.parseInt(wurzel);
            }
        catch (Exception e) {
            System.out.println("Keine gültige Eingabe!");
            }
 
 
        // Verarbeitung
        double x = NewtonRoot.getStartValue(a);
        double xAlt;
        int i = 1;
        
        do {
            xAlt = x;
            x = NewtonRoot.computeRoot(n, x, a);
            System.out.println(i + ". Schritt: " + x);
            
        } while (!NewtonRoot.isCloseEnough(x, xAlt));
        
 
    }
 
    static class NewtonRoot {
 
        static double computeRoot (int n, double x, double a) {
            return x - ((Math.pow(x, n) - a)/(n * Math.pow(x, n - 1)));
        }
 
        static double getStartValue (double x) {
            return x / 10;
        }
 
        
 
        static boolean isCloseEnough (double x1, double x2) {
            return Math.abs (x1 - x2) < 1E-10;
        }
 
 
    }
 
}

Wie Du siehst, habe ich die Methode doApproximationStep rausgeschmissen, ich glaube, da hast Du irgend etwas durcheinander gebracht, computeRoot ist ja schon eine Näherung.

Die Formel in computeRoot war m.E. verkehrt. Eine Formel wie "x Hoch n" schreibt man in Java:

Code:
Math.pow(x, n);

Dann waren da noch ein paar Tippfehler, die sind auch raus.
 
Hey, super, endlich mal zu sehen dass es im kern lauffähig ist. Danke!

Einziges Problem: Der die Funktion doApproximationStep soll halt in der Klasse NewtonRoot vorhanden sein, es müsste doch reichen die schleife aus der verarbeitung als Methode zu speichern, und dann in der Verarbeitung per Methodenaufruf darauf zurückzugreifen, oder?

Schleifeninkrementierung für die Schrittangabe hattest du noch vergessen,die hab ich schnell noch eingefügt.

Neben der doApproximationStep methode ist nur noch eine Sache, die mich wundert: In der aufgabenbeschreibung (wie im post oben zu sehen, soll die Ausgabe als 1.Schritt 1 liefern...nur frage ich mich, wo soll der herkommen...? müsste ja dann x/10 sein (wenn man wie in der Angabe als x= 10 und n= 3 nimmt)...
 
Einziges Problem: Der die Funktion doApproximationStep soll halt in der Klasse NewtonRoot vorhanden sein, es müsste doch reichen die schleife aus der verarbeitung als Methode zu speichern, und dann in der Verarbeitung per Methodenaufruf darauf zurückzugreifen, oder?

Kanst Du m.E. machen, der Näherungsschritt ist eigentlich der Aufruf von computeRoot(),

Schleifeninkrementierung für die Schrittangabe hattest du noch vergessen,die hab ich schnell noch eingefügt.

Stimmt 😳

Neben der doApproximationStep methode ist nur noch eine Sache, die mich wundert: In der aufgabenbeschreibung (wie im post oben zu sehen, soll die Ausgabe als 1.Schritt 1 liefern...nur frage ich mich, wo soll der herkommen...? müsste ja dann x/10 sein (wenn man wie in der Angabe als x= 10 und n= 3 nimmt)...

Nach meinem Verständnis ist der erste Näherungswert das Ergebnis des ersten Aufrufs von computeRoot() - so wie ich es in meiner Schleife dargestellt habe. Der Anfangswert ist ja ein beliebiger Wert (außer 0). Die Näherung funktioniert auch mit x / 4 oder x / 2 ... als anfangswert.
 
Hallo, ich hab da ein kleines Problem. Bei mir wird das IOExcepion nicht erkannt.

New.java:5: cannot find symbol
symbol : class IOException
location: class New
public static void main<Srting[] argv> throws IOExcention {
^

ich hoffe es kann mit jemand helfen
 
...du musst es natürlich eingangs importieren, sonst kann er mit der Anweisung nix anfangen.

Also import java.io.*;
 

Zurück
Oben