06-11337 Introduction to Computer Science The University of Birmingham Autumn Semester 2002 School of Computer Science

November 4, 2002 ­c Achim Jung and Uday Reddy Handout 8 Loops

1. Using branching to save code. On Handout 5 we saw how by giving the processor control over its program counter we can implement alternative execution paths:

flow diagram: machine code: condition

branch if positive no yes

condition

C

½

C C ¾ statement ½ statement

branch unconditionally

C ¾

By using two branching instructions we can make sure that although machine instructions are lined up linearly, only one

C C ¾ of the regions ½ and is executed. From this example, it is easy to see how any flow diagram could be translated into machine code. Branching can also be used to avoid a repetition of code, as in the following examples:

infinite loop: while - do loop:

loop body loop body

condition

branch if positive

Ò Ò

Ô Ü ½

2. Example Here is an example program to calculate Ü and store it in a variable . To calculate , we must start with and Ò

multiply it by Ü again and again times. We model this repetition in the program by using the register R1 as a “counter.”

½ Ò Ò The counter starts at ¼ and gets incremented by until it becomes equal to . As long it is less than , the result register

R2 is multiplied by Ü, and the control goes back to the earlier point in the program labelled the beginning_of_loop. The sequence of instructions starting from this point until the BR instruction are said to form a loop.

start: LA R1, 0 LA R2, 1

L R3,

R1 ´ 0 L R4,
R2 ´ 1 begining_of_loop:

CMP R1, R4, R5 no yes

BRGE R5, end_of_loop R1 < n £ MUL R2, R3, R2 R2 ´ R2 x LA R5, 1 R1 ´ R1+1 ADD R1, R5, R1

BR beginning_of_loop P ´ R2 end_of_loop: ST R2,

1 3. Spaghetti code. In a sense, however, branching is too powerful, because it allows us to write programs which are very intricate and hard to understand. Here is an example:

region 1

region 2

The top half looks like an ordinary loop but then from the end of region 2 the program jumps back into the middle of the body of that loop. There is nothing in the design of machine language to preclude such programs. Similarly, the language of flow diagrams also allows arbitrary jumping from one place to another. One speaks of spaghetti code for this “style” of programming. Early programming languages were very close to actual machine code. and BASIC, for example, retain the concept of a numbered list of instructions with jumps from one location to another as the primary control construct. These jumps are introduced by the keyword and simply contain a to tell the compiler or interpreter where to continue with the execution of the program. Although later languages (such as ALGOL, PASCAL, C/C++/JAVA) retain some form of goto, its use is now very much discouraged, and widely considered to be unnecessary. In the remainder of this handout I will try to explain why. 4. . The drive to oust goto began with a landmark paper by Edsger Dijkstra, one of the most influential people in the development of Computer Science. It is called GOTO statement considered harmful and was published in the Communications of the ACM in 1968. A huge debate began which included most eminent computer scientists of the time. The debate is now widely considered to be resolved, with Dijkstra and his concept of structured programming generally being accepted. Structured programming controls the execution flow through a small number of well-defined constructs, none of which include goto. You already know some of these constructs: Branching This class refers to alternative execution paths. In Java the constructs are called if else and switch. Iteration This refers to loops of various shapes. In Java we have three flavours of loops, for, while,anddo - while. Java’s “methods” are to to be mentioned here. I will describe the underlying mechanisms on the next handout. Directives This refers to exceptions and breaks.

In this handout we concentrate on iterative constructs, that is, on loops. 5. The (idealised) for-loop. In algorithmic notation, we might use a for-loop to indicate that some statements must be

repeatedly executed for some designated values of a variable. For example, both the statements: g

for i = 1, 2, ..., n do f ... g

for i = n, n-1, ..., 1 do f ...

½ Ò

say that the statements in the braces (“the loop body”) must be executed for all values of i between and .However,in

i i Ò i Ò the first case, ½ is the first values of and is increased until it reaches . In the second case, starts at and it is decreased

until it reaches ½. A general way of specifying a sequence of values for a variable is provided in the Java’s for-loop statement. It specifies:

¯ a statement for setting the initial value of the variable, called initialisation,

¯ a statement for changing the value of the variable to get the next value of interest, called incrementing,and

¯ a condition that indicates whether the variable is within the sequence of interest, called the loop-condition. The form of the for-loop statement is:

2 for ( ; ; ) ;

The two examples of for-loops above can be expressed in Java as follows:

for (i = 1; i <= n; i = i+1) { ... } for (i = n; i >= 1; i = i-1) { ... }

From a conceptual point of view, an idealised for-loop has the important feaature that, as soon as it is entered, it is known how many iterations will be performed. Thus, a for-loop is a safe construct; it cannot lead to non-termination. Furthermore, in an idealised for-loop the control variable only exists for the time the loop is active and is only available for reading. The for-loop in Java does not strictly adhere to these principles. Its effect in terms of machine language is that the various parts of the declaration

for (A; B; C) D;

are compiled separately and assembled in the order

A start: B Branch if false to continue D C Branch to start continue:

Whether these parts set up a proper counter-controlled loop is not checked. The parts A, C, and D can be arbitrary statements, B can be an arbitrary condition. 6. The while-loops. The idealised for-loop is not sufficient for all programming purposes. There are a number of short-

comings: Æ (a) It can be shown that there are numerical functions (that is, functions from Æ to ) which cannot be programmed using for-loops only. You will hear more about this in the second year module on Models of Computation. (b) An idealised for-loop is controlled by a counter and terminated as soon as that parameter assumes a certain value. There are situations where the terminating condition does not derive from the number of iterations already performed. For example, in a computation with real (= floating point) numbers you may want to repeat an approximation process until your result is stable up to a certain precision. How many iterations are needed for this may be difficult to determine in advance. (c) There are situations when you repeatedly have to deal with input from some other process (or the keyboard) which is not under your control. Then the number of repetitions is unpredictable by principle. You may even have to repeat forever. A more general programming construct than the for-loop is given by the while-loop. In Java the syntax is

while (condition) statement;

Its semantics in (meta-)assembly code and as a flowchart is as follows:

start: no yes EVALUATE condition condition BRANCH_IF_FALSE cont EXECUTE statement BRANCH start statement cont: ...

As is the case for the for-loop, the body of a while-loop may not be executed at all because the test is made before the body is entered. The difference is that a while-loop does not provide an automatic or standard way of ensuring that the loop is ever terminated — it can run forever.

3 7. Evaluation of Java’s loop constructs. Let us step back and try to evaluate whether Java’s three loop constructs constitute a good choice. Minimality. It is a good thing to have fewer rather than more constructs in a programming language, because a smaller language means that a programmer needs to get familiar with fewer concepts. In my opinion, Java strikes a good balance in this respect, although its set of constructs is not minimal at all, as the following theorem by B¨ohm and Jacobini illustrates: Theorem Every flow diagram can be implemented with if-then-else and while only. The proof is not hard at all and you may want to think about it yourself. Naturality. This is the question whether naturally occurring programming tasks have a direct implementation in Java,or whether some kind of trickery is necessary in certain situation. Let’s look at three possible extensions: Often, an iteration is for a fixed number of rounds only but a counter is not explicitly needed in the body of the loop. For such cases, it would be nice to have a construct of the form: repeat times ; To be forced in such situations to introduce a counter explicitly and to make the right choices about initial value and final value seems distracting. Another often cited example is the problem of reading from a stream. Here we are reading items from some data source until the end of the stream is indicated. The natural flow diagram for such a task seems to be

read data item

end + of file?

-

process data item

but structured programming does not allow us to leave a loop at an arbitrary point, only at the beginning (while or at the end (do - while). However, it is possible to code it using a while-loop, accepting a certain amount of code repetition: read-first-data-item; while (! end-of-stream) { process-data-item; read-next-data-item; } Finally, it may well be that a loop is controlled by two quite independent conditions. The prime example is searching an array for the first occurrence of a certain value. Such a search should be terminated if either the value is found or the end of the array is reached. 8. The break statement Java provides a statement called break for abnormally exiting from a structured loop statement (either for or while). For example, the array-searching program mentioned above can be coded as:

for (i = 0; i < n; i = i+1) { if (array[i] is the value being searched for) break; }

This loop terminates as soon as the value is found at some position in the array. That is the effect of the break statement. However, there is also the possibility that the value is not found at any position. In that case, the loop terminates normally (when i reaches n). Since both kinds of termination cause the control to reach the next statement after the loop, some other mechanism must be found to distinguish between the two cases. For example, a boolean variable can be used to distinguish them:

found = false; for (i = 0; i < n; i = i+1) { if (array[i] is the value being searched for) { found = true; break; } }

4