Start Lecture #7
Remark:
There are four parts to a loop and hence 4 tasks for the programmer to accomplish.
As you have seen in Python and we shall see in Java, loops can be quite varied. For one thing the body can be almost arbitrary. For now let's assume that the body is the quadratic equation solver that we have written in class. Currently it just solves one problem and then terminates. How can we improve it to solve many quadratic equations?
final int n=10; int i = 0; while (i<n) { // input A, B, C // solve one equation i++; }
n=getInput.nextInt(); int i = 0; while (i<n) { // input A, B, C // solve one equation i++; }
// input A, B, C while (A!=0 || B!=0 || C!=0) { // solve one equation // input A, B, C }
while (true) { // input A, B, C if (A==0 && B==0 && C=0) { break; } // solve one equation }
There are at least four techniques, each of which can be applied to many different problems.
extra.
extra.
import java.util.Scanner; public class Quadratic5 { public static void main (String[] Args) { System.out.println("Solving quadratic equations Ax^2 + Bx + C"); // The next line is for hardwiring; we are reading the count // final int count = 10; int count; System.out.println("How many equations are to be solved?"); Scanner getInput = new Scanner(System.in); count = getInput.nextInt(); while (count-- > 0) { System.out.println("Enter real numbers A, B, C"); double A = getInput.nextDouble(); double B = getInput.nextDouble(); double C = getInput.nextDouble(); double discriminant = B*B - 4.0*A*C; double ans; if (A == 0) { System.out.println("A linear equation; only one root"); ans = -C/B; System.out.println("The one root is " + ans); } else if (discriminant < 0) { System.out.println("No (real) roots"); } else if (discriminant == 0) { System.out.println("One (double) root"); ans = -B/(2*A); System.out.println("The double root is/are " + ans); } else { // discriminant > 0 double ans1 = (-B + Math.pow(discriminant,0.5))/(2.0*A); double ans2 = (-B - Math.pow(discriminant,0.5))/(2.0*A); System.out.println("The roots are " + ans1 + " and " + ans2); } } } }
On the right is the code for a yet further improved quadratic equation solver. This code illustrates several of the points made above.
import java.util.Scanner; public class SumN { public static void main (String[] args) { Scanner getInput = new Scanner(System.in); double x, sum; int i, n; while (true) { System.out.println("How many numbers do you want to add?"); n = getInput.nextInt(); if (n < 0) { break; } System.out.printf("Enter %d numbers: ", n); i = 0; sum = 0; while (i++ < n) { x = getInput.nextDouble(); sum += x; } System.out.printf("The sume of %d values is %f\n", n, sum); } } }
On the right is a simple program to sum n numbers. Since it does not make sense to sum a negative number of numbers, we let n<o be the sentinel that ends the program.
There are again a few points to note.
n and 1/2times loop: The first part of the body is executed one more time than the second part.
public class UseEOF { final static int EOF = -1; public static void main(String[] args) { int c; while ( (c = nextCharOrEOF()) != EOF) { System.out.write(c); } System.out.flush(); } public static int nextCharOrEOF() { try { return System.in.read(); } catch (java.io.IOException e) { return EOF; } } }
On the right is a very simple loop that is terminated by EOF (end-of-file). However, it does use an advanced feature of Java, namely exceptions.
The method (think of function) nextCharOrEOF either returns the next character from System.in or it returns the value EOF.
EOF is not special; it is declared in the program.
The magic is the try/catch mechanism. The read() method will raise an exception, namely an IOException if the end of file is reached. This is caught by nextCharOrEOF and the value EOF is returned instead of the value returned by read().
As you know System.in is normally the keyboard and System.out is normally the display. However, they can be redirected to be an ordinary file in the file system. When System.in is redirected to a file f, input is taken from f instead of the keyboard, and when System.out is redirected to a file g, output goes to g.
For example the program UseEOF with the mysterious implementation, simply copies all its input to its output.
I copied it to i5 so we can run it (ignore how it works).
If we type simply java UseEOF, then whatever we type will appear on the screen.
If we type instead java UseEOF <f, then the file f will appear on the screen.
Similarly java UseEOF <f >g copies the file f to the file g.
As we have seen a while loop repeatedly performs a test-action sequence: first a BE is tested and then, if the test passes, the body is executed.
do { stmts } while (BE);
In particular, if the test fails initially, the body is not executed at all.
Most of the time, this is just what is wanted; however, there are occasions when we want the body to be first and the test second. In such situations we use a do-while loop.
We see the code skeleton for this loop on the near right and the flowchart on the far right.
final int quota = 250; int count=0; do { count++; } while ((quota-=getInput.nextInt()) > 0); System.out.printf("Needed %d values.\n", count);
In the code on the right a quota is hardwired for brevity. Then the user inputs a series of numbers (say the dollar value of a sale). When he finally reaches or surpasses the quota, the program ends and reports how many values were needed.
Recall the four components of a loop as stated in 4.2.2
Parts 1, 2, and 4 can all be written in one for statement. After the word for comes a parenthesize list with three elements separated by semicolons. The first component is the initialization, the second the test, and the third the update to prepare for the next iteration.
The first code shown on the right presents the for loop corresponding to the example mentioned in the list. Indeed, this is a common usage of for, to have a counter step through consecutive values.
for(i=0; i<10; i++){ body }
for(int i=0; i<10; i++)
for(i=0, j=n; i*j < 100; i++, j--)
for( ; ; )
The second for on the right shows that the loop variable can be declared in the for itself. One effect of this declaration is that the variable, i in this case, is not visible outside the loop. If there was another declaration of i outside, that variable would be inaccessible inside the loop.
It is also possible to initialize and update more than one variable as the third example shows.
Finally, the various components can be omitted, in which case the omitted item is essentially erased from the flowchart. For example, if the first component is omitted, there is no initialization performed; if the middle item is omitted there is no test (it is better to say that the test always yield true); and, if the third item is omitted there is no update. So the last, rather naked for will just keep executing the body until some external reason ends the loop (e.g., a break).
Homework: 4.5, 4.1 (the book forgot to show inputing the number of numbers), 4.9
They are equivalent. Any loop written with one construct can be written with either of the other two.
The for loop puts all the non-body in one place. If these pieces are small, e.g., for(i=0;i<n;i++), this is quite convenient. If they are large and or complicated, the while form is generally easier to read.
Much of this is personal preference.
I don't believe there is a right
or wrong
answer.
We have already done a nested loop in section 4.2.4.
for (int i=1; i<n-1; i++) { for (int j=i+1; j<n; j++) { // if the ith element exceeds the jth, // swap them } }
It is essentially the same as in Python or any other programming language. The inner loop is done repeatedly for each execution of the outer loop.
For example, once we learn about arrays, we will see that the code on the right is a simple (but, alas, inefficient) way to sort an array.
This concerns the hazards of floating point arithmetic. Although we will not be emphasizing numeric errors, two general points can be made.
Given two positive integers, the book just tries every number from one up to the smaller input and chooses the largest one that divides both of the inputs.
Let try a different way to get the GCD. Keep subtracting the smaller from the larger until you get a zero, at which point the nonzero value is the GCD (if they are equal call one of them larger).
(54, 36) → (18, 36) → (18, 18) → (18, 0).
(7, 6) → (1, 6) → (1, 5) → ... → (1, 1) →
(1, 0).