Wie schachtelt man Wurzeln ein?

Zitronentee

Mitglied
Hallo zusammen

Ich habe vor drei Tagen begonnen mit Java zu arbeiten. Nun steht mir folgende Aufgabe im Weg.

Sie lautet: Schreibe eine Klasse, deren main-Methode für eine beliebig reelle Zahl b die zugehörige Wurzel (Wurzel aus b) auf fünf Nachkommastellen genau bestimmt und zusätzlich angibt, wie viele Rechenschritte dafür gebraucht wurden.

Ich dachte, ich kann diese Wurzel mit einschachteln lösen. Also ungefähr so:

(1^2)<3<(2^2)
Dann jeweils das Quadrat testen: 1,1. 1,2. 1,3 ... 1,9.
Falls eine Zahl grösser als 3, nehme diese Zahl (angenommen es wäre 1.2) und subtrahiere 0.1. Danach teste diese Zahl in 0.01 Schritten bis zu der Zahl die wiederum grösser als 3 ist.
1,11. 1,12. 1,13. ... 1,19.
Falls Zahl grösser als 3, nehme diese Zahl(angenommen es wäre 1.21 und subtrahiere nun 0.01.
Dann weitertesten bis zur Zahl die quadriert grösser als 3 ist. Jetzt in 0.001-Schritten.
1,111. 1,112. 1,113. ... 1,119
usw. bis fünf Nachkommastellen erreicht sind.

Ich habe nun ein ziemlich grosses Problem. Ich kenne bisher nur for/if-Schleifen, habe keine Ahnung wie ich einen Zähler einbauen soll und erst recht nicht wie ich den Befehl ausführen soll: Nimm diese Zahl subtrahiere x und verwende die neue Zahl in der neuen for-Schleife und teste dann in diesen Schritten usw. ohne die Variabeln zu verlieren etc, da ich diese ja immer nur in der For-Schleife behalten kann. So komme ich zum Problem, dass ich in einer for-schleife, 5 andere hätte jeweils mit if-Bedingung.

Ich wusste erst nicht einmal wie ich eine for-schleife unterbrechen kann, die Einführung in Java die ich geniessen darf ist richtig schlecht und die Aufgaben für einen Beginner, finde ich ziemlich übetrieben, wenn man nichtmal weiss, wie man grundlegende Sachen ausführt.

Mein Prog sieht bisher so aus und funktioniert nicht, da es in Endlosschleifen ausartet. Ich habe deshalb die restlichen For-Schleifen mal gelöscht, da es schon hier hapert.

Java:
public class Wurzelrechner 
{
	public static void main(String[] args)
	{	int a = 3;
			for (int i=1; i<=a; i++)
			{ 
				if (i*i > a)
					{ 	
                                                                             System.exit(0);
					}
				for ( i= i-1; i-1<=i; i += 0.1 )
				{
					if (i*i > a)
					{
                                                                             System.exit(0);
					}
				}
			System.out.print(i);
                               }
	}
}
Villeicht ist mein vorgehen auch viel zu kompliziert und ihr hättet mir eine einfachere Lösungsidee.

Ich entschuldige mich der Rechtschreibung. In meiner Verzweiflung blieb keine Zeit dies gründlich zu prüfen! :p

--- Wieso muss ich dem System.exit() eigentlich einen Wert zuordnen?

Gruss Zitronentee
 
Zuletzt bearbeitet:

Zitronentee

Mitglied
Danke für die schnelle Antwort.

Ich werde mal versuchen, das Heron-Verfahren zu implementieren, dann habe ich sicherlich mal etwas =)

Wir sollten jedoch eine eigene Methode herausfinden, um sich der Wurzel zu nähern. Auch wenn dies vermutlich viel viel umständlicher rauskommt ;)

Zitro
 

Illuvatar

Top Contributor
Ich denke, es wurde jetzt schon ausführlich genug gesagt, dass das Lösungsverfahren aus dem ersten Post für die produktive Verwendung natürlich nicht gut geeignet ist.
Um Basics wie if oder for zu lernen, ist es aber möglicherweise doch gut.
Außerdem will Zitronentee bestimmt wissen, wie man diesen Algorithmus denn jetzt in Java hätte schreiben können. Also:

Du hast recht, mit einer for-Schleife ist das nicht so richtig einfach zu lösen. Gehen wir nochmal einen Schritt zurück, und überlegen, was es denn ist, was wir 5 mal machen wollen.
Wir wollen einen Zahlenbereich (der kann jedes mal anders sein!) mit einer gewissen Schrittweite (die auch!) durchgehen, und möchten als Resultat einen kleineren Zahlenbereich erhalten, in dem die Wurzel liegen muss.

Dafür bietet es sich an, eine Funktion zu schreiben. Ich gebe dir mal den Rumpf vor:
Java:
/* Returns the new lower bound for the root,
   the square root of input will always be greater than or equal to the result and smaller than result + step. */
public double approximateRoot(double input, double lowerBound, double upperBound, double step) {
  // ???
}
Da ich dich jetzt nicht damit verwirren will, dass wir eigene Klassen erstellen, kann nur eine Zahl zurückgegeben werden. Wir legen fest, dass die zurückgegebene Zahl die untere Grenze des neuen Bereiches sein soll.

Die kann jetzt derart verwendet werden:
Java:
double input, lowerBound, upperBound, step // müssen initialisiert werden;

// ...

double result = approximateRoot(input, lowerBound, upperBound, step);
double newLowerBound = result;
double newUpperBound = result + step;
double newStep = step / 10.0;
Das ist nun eine Iteration, und du kannst dir noch überlegen, wie man die Variablen initialisiert und dann diese Iteration in eine Schleife packt. :)
 
Zuletzt bearbeitet:

Zitronentee

Mitglied
Danke dir vielmals Illuvatar :)

Also kann ich mit der herkömmlichen "public static void main(String[] args)" - Methode/Funktion keine Iterationen mit for-Schleifen schreiben?

Gruss Zitro
 

Landei

Top Contributor
Wenn du alle "Zehnerstellen" des Intervalls durchprüfst, machst du es dir nur unnötig kompliziert: Nimm einfach immer die Mitte des Intervalls. Ist das Quadrat des Mittelwertes kleiner als gewünscht, ist das die neue Untergrenze, ansonsten die neue Obergrenze. Und dann das Ganze von vorn, bis die gewünschte Genauigkeit erreicht wird.

Hier eine mögliche Implementierung:

Java:
public class Root {

    private static double EPSILON = 0.00000001; //darüber steuerst du die Genauigkeit

    public static double root(double x) {
        double lowerBound = 0;
        double upperBound = x;
        while (upperBound - lowerBound > EPSILON) {
            double middle = (lowerBound + upperBound) / 2;
            if (middle * middle < x) {
                lowerBound = middle;
            } else {
                upperBound = middle;
            }
        }
        return lowerBound;
    }

    public static void main(String[] args) {
        System.out.println(root(3));
        System.out.println(Math.sqrt(3)); //das "exakte" Ergebnis
    }
}

Wie schon gesagt ist das bestimmt nicht die effizienteste Methode dafür, aber dafür recht leicht zu verstehen.

Also kann ich mit der herkömmlichen "public static void main(String[] args)" - Methode/Funktion keine Iterationen mit for-Schleifen schreiben?

Ich benutze hier while, aber prinzipiell ist das eine Frage der Bequamlichkeit: Jede [c]while[/c]-Schleife kann als [c]for[/c]-Schleife geschrieben werden und umgekehrt.

Natürlich kannst du in [c]main[/c] auch ein [c]for[/c] reinschreiben, es ist eine ganz normale statische Methode, es ist in diesem Fall nur wenig sinnvoll: Deine Wurzel-Funktion soll ja auch von anderen Klassen aus benutzt werden können, deshalb ist es gut, diese Funktionalität in eine separate Methode zu packen.

Generell sollte eine Methode immer nur eine Aufgabe ausführen, so sollte etwa die Berechnung eines Wertes von seiner Ausgabe getrennt werden u.s.w. (was ist etwa, wenn man später mal eine Webseite oder eine Swing-Anwendung statt der Konsole benutzt?). Dahinter steht Onkel Bob's "Single Responsibility Principle", das (im Gegensatz zur Wikipedia-Meinung) für Methoden, Klassen und Module gilt: Single-Responsibility-Prinzip ? Wikipedia
 
Zuletzt bearbeitet:

Zitronentee

Mitglied
Super. Ihr habt mir ungemein viel geholfen! Nun verstehe ich auch, was Methoden genau sind und wie ich meine eigene definieren kann. Ich habe die while-Schleife kennengelernt, was mir sicherlich auch hilft, da ich es in bestimmten Fällen schwieriger finde, eine korrekte For-Schleife zu implementieren. Da bietet mir die While-Schleife ein bisschen mehr Freiheit!

Ich habe nun ein Programm für den Heron-Algo geschrieben, meine eigene Methode und die von euch!

Ich wünsche euch einen schönen Tag!

Gruss Zitro
 
Zuletzt bearbeitet:
Ähnliche Java Themen
  Titel Forum Antworten Datum
P JTree mit mehreren Wurzeln Java Basics - Anfänger-Themen 2
S Wurzeln Java Basics - Anfänger-Themen 2

Ähnliche Java Themen

Neue Themen


Oben