Earlier we examined the for loop, which executes a set of statements a definite number of times specified by the programmer. In many situations, however, the number of iterations in a loop is unpredictable. The loop eventually completes its work, but only when a condi- tion changes. For example, the user might be asked for a set of input values. In that case, only the user knows the number she will enter. The program’s input loop accepts these val- ues until the user enters a special value or sentinel that terminates the input. This type of process is called conditional iteration, meaning that the process continues to repeat as long as a condition remains true. In this section, we explore the use of the while loop to describe conditional iteration.
The Structure and Behavior of a while Loop
Conditional iteration requires that a condition be tested within the loop to determine whether the loop should continue. Such a condition is called the loop’s continuation condition. If the continuation condition is false, the loop ends. If the continuation condition is true, the statements within the loop are executed again. The while loop is tailor-made for this type of control logic. Here is its syntax:
while <condition>:
<sequence of statements>
The form of this statement is almost identical to that of the one-way selection statement.
However, the use of the reserved word while instead of if indicates that the sequence of statements might be executed many times, as long as the condition remains true.
Clearly, something eventually has to happen within the body of the loop to make the loop’s continuation condition become false. Otherwise, the loop will continue forever, an error known as an infinite loop. At least one statement in the body of the loop must update a variable that affects the value of the condition. Figure 3-6 shows a flow diagram for the semantics of a while loop.
Figure 3-6 The semantics of a while loop true
false
?
statement
Copyright 2019 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
87 Conditional Iteration: The while Loop
The following example is a short script that prompts the user for a series of numbers, computes their sum, and outputs the result. Instead of forcing the user to enter a definite number of values, the program stops the input process when the user simply presses the return or enter key. The program recognizes this value as the empty string. We first present a rough draft in the form of a pseudocode algorithm:
set the sum to 0.0 input a string
while the string is not the empty string convert the string to a float
add the float to the sum input a string
print the sum
Note that there are two input statements, one just before the loop header and one at the bot- tom of the loop body. The first input statement initializes a variable to a value that the loop condition can test. This variable is also called the loop control variable. The second input statement obtains the other input values, including one that will terminate the loop. Note also that the input must be received as a string, not a number, so the program can test for an empty string. If the string is not empty, we assume that it represents a number, and we con- vert it to a float. Here is the Python code for this script, followed by a trace of a sample run:
theSum = 0.0
data = input("Enter a number or just enter to quit: ") while data != "":
number = float(data) theSum += number
data = input("Enter a number or just enter to quit: ") print("The sum is", theSum)
Enter a number or just enter to quit: 3 Enter a number or just enter to quit: 4 Enter a number or just enter to quit: 5 Enter a number or just enter to quit:
The sum is 12.0
On this run, there are four inputs, including the empty string. Now, suppose we run the script again, and the user enters the empty string at the first prompt. The while loop’s condition is immediately false, and its body does not execute at all! The sum prints as 0.0, which is just fine.
The while loop is also called an entry-control loop, because its condition is tested at the top of the loop. This implies that the statements within the loop can execute zero or more times.
Count Control with a while Loop
You can also use a while loop for a count-controlled loop. The next two code segments show the same summations with a for loop and a while loop, respectively.
Copyright 2019 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
88
# Summation with a for loop theSum = 0
for count in range(1, 100001):
theSum += count print(theSum)
# Summation with a while loop theSum = 0
count = 1
while count <= 100000:
theSum += count count += 1 print(theSum)
Although both loops produce the same result, there is a tradeoff. The second code segment is noticeably more complex. It includes a Boolean expression and two extra statements that refer to the count variable. This loop control variable must be explicitly initialized before the loop header and incremented in the loop body. The count variable must also be examined in the explicit continuation condition. This extra manual labor for the programmer is not only time-consuming but also potentially a source of new errors in loop logic.
By contrast, a for loop specifies the control information concisely in the header and auto- mates its manipulation behind the scenes. However, we will soon see problems for which a while loop is the only solution. Therefore, you must master the logic of while loops and also be aware of the logic errors that they could produce.
The next example shows two versions of a script that counts down, from an upper bound of 10 to a lower bound of 1. It’s up to you to decide which one is easier to understand and write correctly.
# Counting down with a for loop for count in range(10, 0, –1):
print(count, end = " ")
# Counting down with a while loop count = 10
while count >= 1:
print(count, end = " ") count -= 1
The while True Loop and the break Statement
Although the while loop can be complicated to write correctly, it is possible to simplify its structure and thus improve its readability. The first example script of this section, which contained two input statements, is a good candidate for such improvement. This loop’s structure can be simplified if we receive the first input inside the loop and break out of the loop if a test shows that the continuation condition is false. This implies postponing the actual test until the middle of the loop. Python includes a break statement that will allow us to make this change in the program. Here is the modified script:Copyright 2019 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
89 theSum = 0.0
while True:
data = input("Enter a number or just enter to quit: ") if data == "":
break
number = float(data) theSum += number
print("The sum is", theSum)
The first thing to note is that the loop’s entry condition is the Boolean value True. Some readers may become alarmed at this condition, which seems to imply that the loop will never exit. However, this condition is extremely easy to write and guarantees that the body of the loop will execute at least once. Within this body, the input datum is received. It is then tested for the loop’s termination condition in a one-way selection statement. If the user wants to quit, the input will equal the empty string, and the break statement will cause an exit from the loop. Otherwise, control continues beyond the selection statement to the next two statements that process the input.
Our next example modifies the input section of the grade-conversion program to continue taking input numbers from the user until she enters an acceptable value. The logic of this loop is similar to that of the previous example.
while True:
number = int(input("Enter the numeric grade: ")) if number >= 0 and number <= 100:
break else:
print("Error: grade must be between 100 and 0") print(number) # Just echo the valid input
A trial run with just this segment shows the following interaction:
Enter the numeric grade: 101
Error: grade must be between 100 and 0 Enter the numeric grade: –1
Error: grade must be between 100 and 0 Enter the numeric grade: 45
45
Some computer scientists argue that a while True loop with a delayed exit violates the spirit of the while loop. However, in cases where the body of the loop must execute at least once, this technique simplifies the code and actually makes the program’s logic clearer. If you are not persuaded by this reasoning and still want to test for the continuation and exit at the top of the loop, you can use a Boolean variable to control the loop. Here is a version of the numeric input loop that uses a Boolean variable:
done = False while not done:
number = int(input("Enter the numeric grade: ")) if number >= 0 and number <= 100:
done = True else:
print("Error: grade must be between 100 and 0") print(number) # Just echo the valid input
Conditional Iteration: The while Loop
Copyright 2019 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
90
For a classic discussion of this issue, see Eric Roberts’s article “Loop Exits and Structured Programming: Reopening the Debate,” ACM SIGCSE Bulletin, Volume 27, Number 1, March 1995, pp. 268–272.
Although the break statement is quite useful when it controls a loop with at least one itera- tion, you should primarily use it for a single exit point from such loops.
Random Numbers
The choices our algorithms have made thus far have been completely determined by given conditions that are either true or false. Many situations, such as games, include some randomness in the choices that are made. For example, we might toss a coin to see who kicks off in a football game. There is an equal probability of a coin landing heads-up or tails-up. Likewise, the roll of a die in many games entails an equal proba- bility of the numbers 1 through 6 landing face-up. To simulate this type of randomness in computer applications, programming languages include resources for generating random numbers. Python’s random module supports several ways to do this, but the easiest is to call the function random.randint with two integer arguments. The func- tion random.randint returns a random number from among the numbers between the two arguments and including those numbers. The next session simulates the roll of a die 10 times:
>>> import random
>>> for roll in range(10):
print(random.randint(1, 6), end = " ") 2 4 6 4 3 2 3 6 2 2
Although some values are repeated in this small set of calls, over the course of a large num- ber of calls, the distribution of values approaches true randomness.
We can now use random.randint, selection, and a loop to develop a simple guessing game. At start-up, the user enters the smallest number and the largest number in the range. The computer then selects a number from this range. On each pass through the loop, the user enters a number to attempt to guess the number selected by the com- puter. The program responds by saying “You’ve got it,” “Too large, try again,” or “Too small, try again.” When the user finally guesses the correct number, the program con- gratulates him and tells him the total number of guesses. Here is the code, followed by a sample run:
import random
smaller = int(input("Enter the smaller number: ")) larger = int(input("Enter the larger number: ")) myNumber = random.randint(smaller, larger) count = 0
while True:
count += 1
userNumber = int(input("Enter your guess: ")) if userNumber < myNumber:
print("Too small!")
Copyright 2019 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
91 elif userNumber > myNumber:
print("Too large!") else:
print("Congratulations! You've got it in", count, "tries!")
break
Enter the smaller number: 1 Enter the larger number: 100 Enter your guess: 50
Too small!
Enter your guess: 75 Too large!
Enter your guess: 63 Too small!
Enter your guess: 69 Too large!
Enter your guess: 66 Too large
Enter your guess: 65 You've got it in 6 tries!
Note that our code is designed to allow the user to guess the number intelligently, by start- ing at the midpoint between the two initial numbers and eliminating half the remaining numbers with each incorrect guess. Ideally, the user should be able to guess the correct number in no more than log2 (upper – lower 1 1) attempts. You will explore the concept of log2 in the exercises and projects.
Loop Logic, Errors, and Testing
You have seen that the while loop is typically a condition-controlled loop, meaning that its continuation depends on the truth or falsity of a given condition. Because while loops can be the most complex control statements, to ensure their correct behavior, careful design and testing are needed. Testing a while loop must combine elements of testing used with
for loops and with selection statements. Errors to rule out during testing the while loop include an incorrectly initialized loop control variable, failure to update this variable cor- rectly within the loop, and failure to test it correctly in the continuation condition. More- over, if one simply forgets to update the control variable, the result is an infinite loop, which does not even qualify as an algorithm! To halt a loop that appears to be hung during testing, type Control1c in the terminal window or in the IDLE shell.
Genuine condition-controlled loops can be easy to design and test. If the continuation con- dition is already available for examination at loop entry, check it there and provide test data that produce 0, 1, and at least 5 iterations.
If the loop must run at least once, use a while True loop and delay the examination of the termination condition until it becomes available in the body of the loop. Ensure that some- thing occurs in the loop to allow the condition to be checked and a break statement to be reached eventually.
Conditional Iteration: The while Loop
Copyright 2019 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
92
exercises
1. Translate the following for loops to equivalent while loops:
a. for count in range(100):
print(count)
b. for count in range(1, 101):
print(count)
c. for count in range(100, 0, –1):
print(count)
2. The factorial of an integer N is the product of the integers between 1 and N, inclu- sive. Write a while loop that computes the factorial of a given integer N.
3. The log2 of a given number N is given by M in the equation N 52 . Using integer M arithmetic, the value of M is approximately equal to the number of times N can be evenly divided by 2 until it becomes 0. Write a loop that computes this approxima- tion of the log2 of a given number N. You can check your code by importing the
math.log function and evaluating the expression round(math.log(N,2)) (note that the math.log function returns a floating-point value).
4. Describe the purpose of the break statement and the type of problem for which it is well suited.
5. What is the maximum number of guesses necessary to guess correctly a given num- ber between the numbers N and M?
6. What happens when the programmer forgets to update the loop control variable in a while loop?
Case stuDy: Approximating Square Roots
Users of pocket calculators or Python’s math module do not have to think about how to compute square roots, but the people who built those calculators or wrote the code for that module certainly did. In this case study, we open the hood and see how this might be done.
request
Write a program that computes square roots.
(continues)
Copyright 2019 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
93 analysis
The input to this program is a positive floating-point number or an integer. The out- put is a floating-point number representing the square root of the input number. For purposes of comparison, we also output Python’s estimate of the square root using
math.sqrt. Here is the proposed user interface:
Enter a positive number: 3
The program's estimate: 1.73205081001 Python's estimate: 1.73205080757
Design
In the seventeenth century, Sir Isaac Newton discovered an algorithm for approximat- ing the square root of a positive number. Recall that the square root y of a positive number x is the number y such that y2 5x. Newton discovered that if one’s initial estimate of y is z, then a better estimate of y can be obtained by taking the aver- age of z together with x / z. The estimate can be transformed by this rule again and again, until a satisfactory estimate is reached.
A quick session with the Python interpreter shows this method of successive approxi- mations in action. We let x be 25 and our initial estimate, z, be 1. We then use New- ton’s method to reset z to a better estimate and examine z to check it for closeness to the actual square root, 5. Here is a transcript of our interaction:
After three transformations, the value of z is exactly equal to 5, the square root of 25. To include cases of numbers, such as 2 and 10, with irrational square roots, we can use an initial guess of 1.0 to produce floating-point results.
>>> x = 25
>>> y = 5
>>> z = 1
# The actual square root of x
# Our initial approximation
>>> z = (z + x / z) / 2
>>> z
# Our first improvement
13.0
>>> z = (z + x / z) / 2 # Our second improvement
>>> z 7.0
>>> z = (z + x / z) / 2 # Our third improvement – got it!
>>> z 5.0 (continued )
(continues) Conditional Iteration: The while Loop
Copyright 2019 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
94
We now develop an algorithm to automate the process of successive transforma- tions, because there might be many of them, and we don’t want to write them all.
Exactly how many of these operations are required depends on how close we want our final approximation to be to the actual square root. This closeness value, called the tolerance, can be compared to the difference between and the value of x and the square of our estimate at any given time. While this difference is greater than the tol- erance, the process continues; otherwise, it stops. The tolerance is typically a small value, such as 0.000001.
Our algorithm allows the user to input the number, uses a loop to apply Newton’s method to compute the square root, and prints this value. Here is the pseudocode, followed by an explanation:
set x to the user's input value set tolerance to 0.000001 set estimate to 1.0 while True
set estimate to (estimate + x / estimate) / 2 set difference to abs(x - estimate ** 2) if difference <= tolerance:
break output the estimate
Because our initial estimate is 1.0, the loop must compute at least one new estimate.
Therefore, we use a while True loop. This loop transforms the estimate before determining whether it is close enough to the tolerance value to stop the process.
The process should stop when the difference between the square of our estimate and the original number becomes less than or equal to the tolerance value. Note that this difference may be positive or negative, so we use the abs function to obtain its abso- lute value before examining it.
A more orthodox use of the while loop would compare the difference to the toler- ance in the loop header. However, the difference must then be initialized before the loop to a large and rather meaningless value. The algorithm presented here captures the logic of the method of successive approximations more cleanly and simply.
Implementation (Coding)
The code for this program is straightforward.
"""
Program: newton.py Author: Ken
(continues) (continued )
Copyright 2019 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203