Quadratwurzeln über Newtons Methode in Java
Dieses Mal gibt eines meiner Labors an, dass ich ein vollständiges Java-Programm schreiben muss, das die Quadratwurzel einer Zahl nach Newtons Methode berechnet. Der Grund für die Verwendung der Newton-Methode im Gegensatz zu Math.sqrt(x)ist, dass ich die Verwendung einfacher E / A, bedingter Ausdrücke, Schleifen und verschachtelter Schleifen üben kann.
Die vollständigen Anweisungen lauten wie folgt:
Angenommen, Sie möchten die Quadratwurzel von x berechnen .
Erstens: Wir immer mit einer Vermutung / Angleichung beginnen , daß die Quadratwurzel von Wert für x ist y = 1,0
Als nächstes berechnen wir den Durchschnitt dieses y-Wertes plus den x-Wert geteilt durch den y-Wert .
Diese Gleichung → (y + (x / y)) / 2.
Das Ergebnis der Lösung dieser Gleichung wird dann zur neuen Approximation der Quadratwurzel (dem neuen y- Wert). Dieser neue y- Wert liegt näher am tatsächlichen Wert für die Quadratwurzel von x als die ursprüngliche y- Schätzung von 1,0
Wiederholen Sie den obigen Schritt mit jedem neuen berechneten Wert für y als neue Schätzung für die Quadratwurzel von x, bis der y-Wert nahe genug ist .
Beispiel: Angenommen, wir möchten die Quadratwurzel von 2 berechnen, dann würde die Berechnung wie folgt ablaufen (alle Werte als doppelt): x = 2,0 und y = 1,0
Iteration Guess Quotient Average
Number for y x/y ( y + (x/y) ) / 2
1 1.0 2.0/1.0 => 2.0 (1.0 + 2.0/1.0)/2.0 => 1.5
2 1.5 2.0/1.5 => 1.33333 (1.5 + 1.33333)/2.0 => 1.41666
3 1.41666 2.0/1.41666 => 1.41176 (1.41666 + 1.41176)/2.0 => 1.41421
4 1.41421 etc...
Die Lösung wird erreicht, wenn das Quadrat der Schätzung „gleich“ ist wie der Wert von x (die Definition der Quadratwurzel). Leider kann für die meisten Zahlen die genaue Lösung niemals auf diese Weise erreicht werden, so dass der Prozess für immer fortgesetzt wird. Um sicherzustellen, dass der Berechnungsprozess tatsächlich stoppt, müssen wir die Stoppbedingung der Schleife so ändern, dass sie " nah genug " ist. Nah genug ist die Toleranz (eine kleine Zahl), die wir als gute Annäherung an den genauen Wert akzeptieren.
Nah genug tritt auf, wenn die absolute Differenz zwischen x und (y * y) geringer ist als die Toleranz (vom Benutzer definiert).
Um zu sehen, wie Ihr Programm voranschreitet, drucken Sie die Iterationsnummer und den Schätzwert aus. Verwenden Sie mindestens 8 Stellen nach dem Dezimalwert und 2 Stellen vor der Dezimalstelle. In dem unten gezeigten Beispiellauf werden nur 5 Stellen nach der Dezimalstelle verwendet.
Beispiellauf:
Square Root approximation program
Enter the value : 2.0
Enter the tolerance : 0.00001
Iteration Guess Guess Absolute value
Number value Squared Difference
1 1.00000 1.00000 1.00000
2 1.50000 2.25000 0.25000
3 1.41666 2.00693 0.00693
4 1.41421 1.99999 0.00001
Approximated Square root of 2.0 = 1.41422
Der resultierende Code, den ich geschrieben habe, um dieses Problem zu lösen, lautet wie folgt:
import java.util.Scanner;
/**
* SRN: 507-147-9
*/
public class Lab8_1 {
public static void main(String[] args) {
// new input
Scanner input = new Scanner(System.in);
// define vars
int iteration = 1;
double x, y, guessSquared = 1, quotient, average, tolerance, absValDiff = 1;
y = 1.0;
// program name
System.out.println("Square Root approximation program");
System.out.println();
// prompt variables
System.out.print("Enter the value : "); // prompt x value
x = input.nextDouble(); // store input as "x"
System.out.print("Enter the tolerance : "); // prompt tolerance
tolerance = input.nextDouble(); // store input as "tolerance"
System.out.println();
// print formatted header
System.out.println("Iteration Guess Guess Absolute value");
System.out.println("Number value Squared Difference");
System.out.println();
// print first calculation
System.out.printf("%9d %11.8f %11.8f %11.8f \n", iteration, y, guessSquared, absValDiff);
// increment the value of "iteration" by 1
iteration++;
while (absValDiff > tolerance) {
// looped calculations
quotient = x / y;
average = (y + quotient) / 2;
y = average;
guessSquared = y * y;
absValDiff = Math.abs(x - guessSquared);
// print results per iteration
System.out.printf("%9d %11.8f %11.8f %11.8f \n", iteration, y, guessSquared, absValDiff);
// increment the value of "iteration" by 1
iteration++;
}
// print results
System.out.println();
System.out.printf("Approximated Square root of " + x + " = %11.8f \n", y);
}
}
Damit habe ich eine Frage zur Richtigkeit meiner Antworten im Gegensatz zu denen im Beispiel. Obwohl mathematisch gesehen die richtigen Gleitkommazahlen in meinen Variablen gespeichert sind, wird beim Drucken der Ergebnisse auf der Konsole immer die letzte Ziffer meines Gleitkommas aufgerundet. Aus meiner Sicht ähnelt dies den Rundungsfehlern, die bei einem Taschenrechner auftreten würden, bei dem das Ergebnis der durchgeführten Berechnungen nur ungefähre Darstellungen der tatsächlichen Zahlen sind, da nur rationale Festkommazahlen genau in der Maschine dargestellt werden können.
Ein Beispiel für diese Art von Fehler wäre: 2/3 = 0,666666667
Gibt es eine Möglichkeit, eine festgelegte Länge für meine Variablen mithilfe des printfFormats zu erfassen, ohne zuzulassen, dass die Zahl beim Drucken auf der Konsole aufgerundet wird?
Antworten
Gibt es eine Möglichkeit, eine festgelegte Länge für meine Variablen im printf-Format zu erfassen, ohne zuzulassen, dass die Zahl beim Drucken auf der Konsole aufgerundet wird?
Sie können einen "Trick" verwenden
String output = String.format("%12.9f", doubleValue);
System.out.println(output.substring(0, output.length() - 1);
Ihr Programm sieht bisher ziemlich gut aus. Hier sind einige Dinge, die mir aufgefallen sind:
Es gibt einen logischen Fehler für Ihre erste Iteration bei der Berechnung
absValDiff. Sie initialisieren immerabsValDiffmit 1 und berechnen es nicht für die erste Iteration neu. Wenn Sie also einen Wert wie x = 5 eingeben, wird der Unterschied zwischen Ihrer ersten Schätzung (y = 1) im Quadrat und x nur 1 angegeben. wenn es tatsächlich 4 sein sollte.Infolgedessen bedeutet dies auch, dass das Anfordern einer Toleranz größer oder gleich 1 nicht korrekt funktioniert und das Programm sofort beendet wird. Zum Beispiel nach einer Toleranz von 2 zu fragen, funktioniert nicht richtig.
Möglicherweise können Sie Ihre Kommentare schreiben, um für andere Leser nützlicher zu sein. Sofern Ihnen in Ihrem Kurs nichts anderes gesagt wurde, können Sie davon ausgehen, dass die Person, die Ihren Code liest, versteht, was die Sprache tut, und sich mehr dafür interessiert, warum Ihr Code die Schritte unternimmt, die er tut. Beispielsweise:
// define vars int iteration = 1; double x, y, guessSquared = 1, quotient, average, tolerance, absValDiff = 1;Es ist klar, dass Sie hier Variablen definieren, sodass Sie versuchen können, stattdessen zu erklären, was Sie tun. Warum nicht versuchen, dem Leser zu sagen, wozu die Variablen dienen?
Normalerweise ist es einfacher, Ihre Variablen nach Bedarf zu deklarieren, als alle oben in der Methode. Eine weitere Referenz finden Sie im Abschnitt über Erklärungen hier . Wie in dieser Quelle erwähnt, war es in älteren Programmiersprachen Tradition, alle Ihre Variablen im Voraus zu deklarieren, aber es wird im Allgemeinen nicht als bewährte Methode angesehen, dies jetzt zu tun.
Wenn Sie all dies ändern, sieht Ihr Code möglicherweise folgendermaßen aus:
import java.util.Scanner;
/**
* SRN: 507-147-9
*/
public class Lab8_1 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int iteration = 1; // Counts the current iteration number at each step.
double y = 1.0; // Initial guess for the square root of the number x.
double guessSquared = y * y; // The value y^2 which we want to be close to x.
System.out.println("Square Root approximation program");
System.out.println();
System.out.print("Enter the value : ");
// The number we intend to approximate the square root of.
double x = input.nextDouble();
System.out.print("Enter the tolerance : ");
// The tolerance so that we terminate if |y^2 - x| < tolerance.
double tolerance = input.nextDouble();
System.out.println();
// Compute the initial difference between x and the square of
// the approximate square root.
double absValDiff = Math.abs(x - guessSquared);
// Print formatted header.
System.out.println("Iteration Guess Guess Absolute value");
System.out.println("Number value Squared Difference");
System.out.println();
// Print the results for the first iterate
System.out.printf("%9d %11.8f %11.8f %11.8f \n", iteration, y, guessSquared, absValDiff);
iteration++;
// Iterate using Newton's method until we obtain a value within tolerance of
// the true square root.
while (absValDiff > tolerance) {
// Calculate the new approximation for x using
// Newton's method, where given the previous approximation y,
// the next approximation is given by (y + (x / y)) / 2.
double quotient = x / y;
y = (y + quotient) / 2;
guessSquared = y * y;
// Compute the new difference between the square of our approximation and x.
absValDiff = Math.abs(x - guessSquared);
// Print results per iteration.
System.out.printf("%9d %11.8f %11.8f %11.8f \n", iteration, y, guessSquared, absValDiff);
iteration++;
}
// Print results for the final iteration which was in tolerance.
System.out.println();
System.out.printf("Approximated Square root of " + x + " = %11.8f \n", y);
}
}
Um die Rundung (und stattdessen zu vermeiden kürzen die Zahl), könnten Sie DecimalFormat , wie erläutert hier , wenn Sie einen alternativen Ansatz zu Gilbert Le Blanc Methode wollte. Nach dem Importieren von java.text.DecimalFormatund java.math.RoundingModekönnen Sie es wie folgt verwenden:
DecimalFormat df = new DecimalFormat("#.##");
df.setRoundingMode(RoundingMode.DOWN);
System.out.println(df.format(0.66999f));
was ausgeben würde 0.66.