Lesson 11 - While Loops

The following topics are discussed in this notebook:

  • While loops
  • Reading user input

While Loops

A while loop is similar to a for loop in that it is a tool used to automate a repetive task. The core difference between while and for loops is as follows:

  • A for loop executes a predetermined number of times. A for loop that begins with "for i in range(a,b)" will execute exactly once for each value of the counter i that falls within the given range.
  • A while loop executes as long as some supplied condition is true. Depending on the nature of this condition, we do not necessarily know ahead of time how many times the loop will execute.

The syntax for creating a while loop is as follow:

while condition:
    code to be executed each iteration

The condition in a while statement should be an expression that evaluates to a Boolean value. When Python encounters a while loop, it will check to see if the condition evaluates to True. If it does, then it will step into the loop and perform the first iteration. Each time the loop executes, Python returns to the start of the loop and checks the condition again. As long as the condition evaluates to True, Python will continue executing iterations of the loop. If the condition ever evaluates to False, then Python will stop executing the body of the loop, and will move on to the next lines of code.

The following cell illustrates a simple example of a while loop. The cell prints out the squares of the first five positive integers.

In [1]:
n = 1
while n <= 5:
    print(n**2)
    n += 1
1
4
9
16
25

The task above could have been accomplished more succinctly using a for loop:

In [2]:
for n in range(1,6):
    print(n**2)
1
4
9
16
25

Selecting Between while and for Loops

As it turns out, anything that can be accomplished with a for loop can also be done with a while loop. However, for loops require fewer lines of code than a similar while loop, and are typically easier to read. So why would we ever use a while loop? As it turns out, while loops are a more flexible tool than for loops. There are some tasks that we cannot accomplish with a for loop, but can with a while loop.

When we create a for loop, we tell the loop (either explicitly, or programmatically) how many times it will run. As soon as Python encounters a statement starting with for, it will know how many times that the loop will execute (assuming that no errors are encountered). On the other hand, while loops will continue to execute for as long as some condition is true. Python does not know how many times it will execute a while loop that it enounters, but it will keep doing so until the condition is no longer true. For this reason, while loops are well-suited for situations in which we do not know how many times the loop will need to execute, either because it would be difficult to calculate, or because the condition depends on some external factors (such as user input) that Python has no way of knowing in advance.

As a somewhat superficial example, let's say that you wanted to know the smallest positive integer n for which $n^5 > \left(7 n + 10 \right)^4$. If we could mathematically solve the inequality, we could get the answer, but that is certainly not easy to do. We can, however, simply start n at 1, and then use a while loop to increment n for as long as $n^5 \leq \left(7 n + 10 \right)^4$

In [3]:
n = 1
while n**5 <= (7*n + 10)**4:
    n += 1
    
print(n)
2407
In [4]:
print(n**5)
print((7*n + 10)**4)
80794249545628807
80784351430226161

As a more practical use of while loops, consider the following example.

Example: Counting Loan Payments

Assume that a loan of \$225,000 is being repaid with monthly payments of \\$850, which occur at the end of the month. The loan is collecting interest at a monthly rate of 0.3%. So, at the end of each month, the remaining balance wil be multiplied by 1.003, and then \$850 is deducted from this balance. We can use a while loop to determine the number of monthly payments required to fully repay the loan.

In [5]:
balance = 225000
rate = 0.003
pmt = 950
count = 0

while balance > 0:
    balance = balance * (1 + rate) - pmt
    count += 1
    
print(count)
528

It is very unlikely that amount owed during the last month was exactly \$850. As a result, after the loop finished executing, the balance was likely negative. We can add the payment amount back to the balance to get the amount owed just before the final payment, and thus determine the true size of the last payment.

In [6]:
print(balance + pmt)
515.932909740989

Example: Guessing Game

Programs often require input from the user. Python's input() function provides a method of prompting the user for input. For example, consider the following code:

name = input("What is your name? ")

This code will print the string, "What is your name? " and will then wait for user input. The value entered by the user will then be stored in the variable name.

In [7]:
name = input("What is your name? ")
print("Hello, " + name + "!")
What is your name? Robbie
Hello, Robbie!

User input can be combined with while loops to create interactive programs. Here we implement a simple guessing game in which the user is prompted to try to guess a randomly generate number between 0 and 500.

In [8]:
import random
n = random.choice(range(0, 501))

print("I have selected a random number between 0 and 500, inclusive. Can you guess it?")

done = False
count = 1
while done == False:
    
    guess = int(input("Please enter guess number " + str(count) + ": "))
    
    if(guess < n):
        print("Your guess was too small.")
    elif(guess > n):
        print("Your guess was too large.")
    else:
        print("That's it! It took you " + str(count) + " guesses to find the right answer.")
        done = True
        
    count += 1
    
I have selected a random number between 0 and 500, inclusive. Can you guess it?
Please enter guess number 1: 250
Your guess was too small.
Please enter guess number 2: 375
Your guess was too small.
Please enter guess number 3: 438
Your guess was too large.
Please enter guess number 4: 406
That's it! It took you 4 guesses to find the right answer.

Example: Approximating a Square Root

It is often the case in Computer science and Data Science that some value of interest is calculated by performing a sequence of better and better approximations. In these situations, we might tell our program precisely how many approximations we want it to perform (likely with a for loop). Alternately, we might ask our program to continue to calculate approximations until we have met some condition, such as two subsequent approximations being very near to each other.

In the example below, we will approximate the square root of K = 7,341,234,543,244,549. Our approach will be fairly simple. We will make an initial guess for the square root, which we will call x. We will divide K by x, naming the result y. If our guess was good, then x and y will be very close to each other, and thus close to the actual solution. If our guess was bad, we will set x to be equal to the average of x and y, since the true answer will have to be somewhere between these two approximations.

We will continue this process until x and y are within 1/10000 of each other. So that we know how many times the loop had to run, we will also create a counter n.

In [9]:
K = 7341234543244549

x = 1
y = K/x

n = 0
while abs(x - y) > 0.0001:
    x = (x + y) / 2
    y = K / x
    n += 1

print('Value of x:  ', x)
print('Value of y:  ', y)
print('Value of x*y:', x**2)
print('Iterations:  ', n)
Value of x:   85681004.56486577
Value of y:   85681004.56486577
Value of x*y: 7341234543244549.0
Iterations:   31

Example: Estimating Pi

We will close with one more example drawn from the world of mathematics. It can be proven that the transcendental number $\pi$ can be written as a sum of infinitely many fractions as follows:

$$\pi = \frac{4}{1} - \frac{4}{3} + \frac{4}{5} - \frac{4}{7} + \frac{4}{9} - \frac{4}{11} + ...$$

The more numbers we add in this never-ending series of fractions, the closer our approximation will be to the true value of $\pi$. It can be shown that the amount of error involved in our approximation will be less than the absolute value of the first term from the series that we DID NOT add into the total.

In the cell below, we will add together several terms of this series, stopping when we reach a term whose absolute value is less than 0.00001.

In [10]:
pi_approx = 0

keep_adding = True

n = 0
while keep_adding:
    new_term = 4 / (2*n + 1)
    pi_approx = pi_approx + new_term * (-1)**n
    n += 1
    
    next_term = 4 / (2*n + 1)
    if next_term < 0.00001:
        keep_adding = False
        
print(pi_approx)
print(n)
3.1415876535897618
200000

Note that the first 8 decimal digits of pi are: 3.14159265