“Put your dough into the oven when it is hot: After making sure that it is in fact dough.” —Idries Shah, Learning How to Learn
In almost every program you write for this book, you’re going to instruct the computer to make a decision. You can do this using an important programming tool called conditionals. In programming we can use conditional statements
like “If this variable is more than 100, do this; otherwise, do that” to check whether certain conditions are met and then determine what to do based on the result. In fact, this is a very powerful method that we apply to big problems, and it’s even at the heart of machine learning. At its most basic level, the program is guessing and then modifying its guesses based on feedback.
In this chapter you learn how to apply the guess-and-check method using Python to take user input and tell the program what to print depending on the input. You then use conditionals to compare different numerical values in different mathematical situations to make a turtle wander around the screen randomly. You also create a number-guessing game and use the same logic to find the square root of large numbers.
As you learned in Chapter 2, True and False (which we capitalize in Python) are called Boolean values. Python returns Booleans when comparing two values, allowing you to use the result to decide what to do next. For example, we can use comparison operators like greater than (>) or less than (<) to compare two values, like this:
>>> 6 > 5
True
>>> 6 > 7
False
Here, we ask Python whether 6 is greater than 5, and Python returns True. Then we ask whether 6 is greater than 7, and Python returns False.
Recall that in Python we use one equal sign to assign a value to a variable. But checking for equality requires two equal signs (==), as shown here:
>>> 6 = 6
SyntaxError: can't assign to literal
>>> 6 == 6
True
As you can see, when we try to check using only one equal sign, we get a syntax error. We can also use comparison operators to compare variables:
>>> y = 3
>>> x = 4
>>> y > x
False
>>> y < 10
True
We set the variable y to contain 3, and then set the variable x to contain 4. Then we use those variables to ask whether y is greater than x, so Python returns False. Then we asked whether y is less than 10, which returns True. This is how Python makes comparisons.
You can have your program make decisions about what code to run using if and else statements. For example, if the condition you set turns out to be True, the program runs one set of code. If the condition turns out to be False, you can write the program to do something else or even do nothing at all. Here’s an example:
>>> y = 7
>>> if y > 5:
print("yes!")
yes!
Here, we are saying, assign variable y the value 7. If the value of y is more than 5, print “yes!”; otherwise, do nothing.
You can also give your program alternative code to run using else and elif. Since we'll be writing some longer code, open a new Python file and save it as conditionals.py.
conditionals.py
y = 6
if y > 7:
print("yes!")
else:
print("no!")
In this example we’re saying, if the value of y is more than 7, print “yes!”; otherwise, print “no!”. Run this program, and it should print “no!” because 6 is not larger than 7.
You can add more alternatives using elif, which is short for “else if.” You can have as many elif statements as you want. Here’s a sample program with three elif statements:
conditionals.py
age = 50
if age < 10:
print("What school do you go to?")
elif 11 < age < 20:
print("You're cool!")
elif 20 <= age < 30:
print("What job do you have?")
elif 30 <= age < 40:
print("Are you married?")
else:
print("Wow, you're old!")
This program runs different code depending on which of the specified ranges the value of age falls into. Notice you can use <= for “less than or equal to” and you can use compound inequalities like if 11 < age < 20: for “if age is between 11 and 20.” For example, when age = 50, the output is the following string:
Wow, you're old!
Being able to have your programs make decisions quickly and automatically according to the conditions you define is an important aspect of programming!
Now let’s use what you’ve learned so far to factor a number! A factor is a number that divides evenly into another number; for example, 5 is a factor of 10 because we can divide 10 evenly by 5. In math class, we use factors to do everything from finding common denominators to determining whether a number is prime. But finding factors manually can be a tedious task involving a lot of trial and error, especially when you’re working with bigger numbers. Let’s see how to automate factoring using Python.
In Python you can use the modulo operator (%) to calculate the remainder when dividing two numbers. For example, if a % b equals zero, it means that b divides evenly into a. Here’s an example of the modulo in action:
>>> 20 % 3
2
This shows that when you divide 20 by 3, you get a remainder of 2, which means that 3 is not a factor of 20. Let’s try 5 instead:
>>> 20 % 5
0
Now we get a remainder of zero, so we know that 5 is a factor of 20.
Let’s use the modulo operator to write a function that takes a number and returns a list of that number’s factors. Instead of just printing the factors, we’ll put them in a list so we can use the factors list in another function later. Before we start writing this program, it’s a good idea to lay out our plan. Here are the steps involved in the factors.py program:
Listing 3-1 shows the factors() function. Enter this code into a new file in IDLE and save it as factors.py.
factors.py
def factors(num):
'''returns a list of the factors of num'''
factorList = []
for i in range(1,num+1):
if num % i == 0:
factorList.append(i)
return factorList
Listing 3-1: Writing the factors.py program
We first create an empty list called factorList, which we’ll later fill with the factors as we find them. Then we start a loop, beginning with 1 (we can’t divide by zero) and ending with num + 1, so that the loop will include num. Inside the loop we instruct the program to make a decision: if num is divisible by the current value of i (if the remainder is 0), then the program appends i to the factors list. Finally, we return the list of factors.
Now run factors.py by pressing the F5 key or by clicking Run ▸ Run Module, as shown in Figure 3-1.
Figure 3-1: Running the factors.py module
After running this module, you can use the factors function in the normal IDLE terminal by passing it a number you want to find the factors for, like this:
>>> factors(120)
[1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 24, 30, 40, 60, 120]
You found all the factors of 120 using the factors function! This is much easier and faster than using trial and error.
Now that you know how to instruct a program to make decisions automatically, let’s explore how to let a program execute indefinitely! To start, we’ll make a turtle walk around the screen and use conditionals to make it turn around if it goes beyond a certain point.
The turtle’s window is a classic x-y grid whose x- and y-axes go from –300 to 300 by default. Let’s limit the turtle’s position to anywhere between –200 and 200 for x and y, as shown in Figure 3-2.
Figure 3-2: The rectangle of coordinates the turtle is limited to
Open a new Python file in IDLE and save it as wander.py. First, let’s import the turtle module. To do so, add the following code:
from turtle import *
from random import randint
Note that we also need to import the randint function from the random module to generate random integers.
Now let’s create a function called wander to make the turtle wander around the screen, as shown in Listing 3-2. To do this, we use Python’s infinite while True loop, which always evaluates to True. This will make the turtle wander around without stopping. To stop it, you can click the X on the turtle graphics window.
wander.py
speed(0)
def wander():
while True:
fd(3)
if xcor() >= 200 or xcor() <= -200 or ycor()<= -200 or ycor() >= 200:
lt(randint(90,180))
wander()
Listing 3-2: Writing the wander.py program
First, we set the turtle’s speed to 0, which is the fastest, and then define the wander() function. Inside the function we use the infinite loop, so everything inside while True will execute forever. Then the turtle goes forward three steps (or 3 pixels) and evaluates its position using a conditional. The functions for the x-coordinate and y-coordinate of a turtle are xcor() and ycor(), respectively.
Using the if statement, we tell the program that if any one of the conditional statements is True (the turtle is outside the specified region), then make the turtle turn left a random number of degrees, between 90 and 180, to prevent it from straying. If the turtle is inside the rectangle, the conditional evaluates to False and no code is executed. Either way, the program returns to the top of the while True loop and does fd(3) again.
When you run the wander.py program, you should see something like Figure 3-3.
Figure 3-3: The output of wander.py
As you can see, the turtle walks in a straight line until its x-coordinate gets to 200. (The turtle always starts walking to the right in the positive x-direction.) Then it turns left a random number of degrees, between 90 and 180, and keeps walking straight again. Sometimes the turtle is able to walk outside of the boundary lines, because after the 90-degree turn it’s still pointed off the screen and you’ll see it turning around every loop, trying to get back into the rectangle. This causes the little blobs outside the rectangle you see in Figure 3-3.
You successfully used conditionals to create a turtle that seemed to make decisions on its own! Let’s use conditionals to write an interactive number-guessing program that seems conscious. In this game I think of a number between 1 and 100, and you guess what the number is. How many guesses do you think you would need to guess my number correctly? To narrow down your options, after each incorrect guess, I tell you whether you should guess higher or lower. Fortunately, we can use the average function we wrote in Chapter 2 to make this task infinitely easier.
When you make an incorrect guess, your next guess should depend on whether your guess was too low or too high. For example, if your guess was too low, your next guess should be the middle number between your last guess and the maximum value the number can be. If your guess was too high, your next guess should be the middle number between your last guess and the minimum value the number can be.
This sounds like calculating the average of two numbers—good thing we have the average function! We’ll use it to write the numberGame.py program, which makes smart guesses by narrowing down half the possible numbers every time. You’ll be surprised how quickly you can hone in on the answer.
Let’s take this one step at a time, starting with making a random number generator.
First, we need the computer to choose a number at random between 1 and 100. Create a new file in IDLE and save it as numberGame.py. Then enter the code in Listing 3-3.
number Game.py
from random import randint
def numberGame():
#choose a random number
#between 1 and 100
number = randint(1,100)
Listing 3-3: Writing the numberGame() function
Here, we import the random module and assign a random integer to a variable using the randint() function. Then we create a number variable that will hold a random number between 1 and 100, generated each time we call it.
Now the program needs to ask the user for input so they can take a guess! Here’s an example you can enter into the interactive shell to see how the input() function works:
>>> name = input("What's your name? ")
What's your name?
The program prints the text “What’s your name?” in the shell, asking the user to input their name. The user types something, presses ENTER, and the program saves the input.
We can check whether Python saves the user input to the name variable, like so:
What's your name? Peter
>>> print(name)
Peter
When we ask the program to print name, it prints the user input that was saved in that variable (in this case, Peter).
We can create a function called greet() that we’ll use later in our program:
def greet():
name = input("What's your name? ")
print("Hello, ",name)
greet()
The output will be the following:
>>>
What's your name? Al
Hello, Al
>>>
Try writing a short program that takes the user’s name as input, and if they enter “Peter,” it will print “That’s my name, too!” If the name is not “Peter,” it will just print “Hello” and the name.
Now you know how to work with text that the user inputs, but we’ll be taking in number inputs in our guessing game. In Chapter 2 you learned about basic data types, like integers and floats, that you can use to perform math operations. In Python, all input from users is always taken in as a string. This means that if we want numbers as inputs, we have to convert them to an integer data type so we can use them in operations.
To convert a string to an integer, we pass the input to int(), like this:
print("I'm thinking of a number between 1 and 100.")
guess = int(input("What's your guess? "))
Now whatever the user enters will be transformed into an integer that Python can operate on.
Now the numberGame.py program needs a way to check whether the number the user guessed is correct. If it is, we’ll announce that the guess is right and the game is over. Otherwise, we tell the user whether they should guess higher or lower.
We use the if statement to compare the input to the content of number, and we use elif and else to decide what to do in each circumstance. Revise the existing code in numberGame.py to look like the code in Listing 3-4.
number Game.py
from random import randint
def numberGame():
#choose a random number
#between 1 and 100
number = randint(1,100)
print("I'm thinking of a number between 1 and 100.")
guess = int(input("What's your guess? "))
if number == guess:
print("That's correct! The number was", number)
elif number > guess:
print("Nope. Higher.")
else:
print("Nope. Lower.")
numberGame()
Listing 3-4: Checking for a correct guess
If the random number held in number is equal to the input stored in guess, we tell the user their guess was correct and print the random number. Otherwise, we tell the user whether they need to guess higher or lower. If the number they guessed is lower than the random number, we tell them to guess higher. If they guessed higher, we tell them to guess lower.
Here’s an example of the output so far:
I'm thinking of a number between 1 and 100.
What's your guess? 50
Nope. Higher.
Pretty good, but currently our program ends here and doesn’t let the user make any more guesses. We can use a loop to fix that.
To allow the user to guess again, we can make a loop so that the program keeps asking for more guesses until the user guesses correctly. We use the while loop to keep looping until guess is equal to number, and then the program will print a success message and break out of the loop. Replace the code in Listing 3-4 with the code in Listing 3-5.
number Game.py
from random import randint
def numberGame():
#choose a random number
#between 1 and 100
number = randint(1,100)
print("I'm thinking of a number between 1 and 100.")
guess = int(input("What's your guess? "))
while guess:
if number == guess:
print("That's correct! The number was", number)
break
elif number > guess:
print("Nope. Higher.")
else:
print("Nope. Lower.")
guess = int(input("What's your guess? "))
numberGame()
Listing 3-5: Using a loop to allow the user to guess again
In this example, while guess means “while the variable guess contains a value.” First, we check whether the random number it chose is equal to the guess. If it is, the program prints that the guess is correct and breaks out of the loop. If the number is greater than the guess, the program prompts the user to guess higher. Otherwise, it prints that the user needs to guess lower. Then it takes in the next guess and the loop starts over, allowing the user to guess as many times as needed to get the correct answer. Finally, after we’re done defining the function, we write numberGame() to call the function to itself so the program can run it.
Save the numberGame.py program and run it. Each time you make an incorrect guess, your next guess should be exactly halfway between your first guess and the closest end of the range. For example, if you start by guessing 50 and the program tells you to guess higher, your next guess would be halfway between 50 and 100 at the top of the range, so you’d guess 75.
This is the most efficient way to arrive at the correct number, because for each guess you’re eliminating half the possible numbers, no matter whether the guess is too high or too low. Let’s see how many guesses it takes to guess a number between 1 and 100. Figure 3-4 shows an example.
Figure 3-4: The output of the number-guessing game
This time it took six guesses.
Let’s see how many times you can multiply 100 by a half before you get to a number below 1:
>>> 100*0.5
50.0
>>> 50*0.5
25.0
>>> 25*0.5
12.5
>>> 12.5*0.5
6.25
>>> 6.25*0.5
3.125
>>> 3.125*0.5
1.5625
>>> 1.5625*0.5
0.78125
It takes seven times to get to a number less than 1, so it makes sense that on average it takes around six or seven tries to guess a number between 1 and 100. This is the result of eliminating half the numbers in our range with every guess. This might not seem like a useful strategy for anything but number-guessing games, but we can use this exact idea to find a very accurate value for the square root of a number, which we’ll do next.
You can use the number-guessing game strategy to approximate square roots. As you know, some square roots can be whole numbers (the square root of 100 is 10, for example). But many more are irrational numbers, which are never-ending, never-repeating decimals. They come up a lot in coordinate geometry when you have to find the roots of polynomials.
So how could we possibly use the number-guessing game strategy to find an accurate value for a square root? You can simply use the averaging idea to calculate the square root, correct to eight or nine decimal places. In fact, your calculator or computer uses an iterative method like the number-guessing strategy to come up with square roots that are correct to 10 decimal places!
For example, let’s say you don’t know the square root of 60. First, you narrow your options down to a range, like we did for the number-guessing game. You know that 7 squared is 49 and 8 squared is 64, so the square root of 60 must be between 7 and 8. Using the average() function, you can calculate the average of 7 and 8 to get 7.5, which is your first guess.
>>> average(7,8)
7.5
To check whether 7.5 is the correct guess, you can square 7.5 to see if it yields 60:
>>> 7.5**2
56.25
As you can see, 7.5 squared is 56.25. In our number-guessing game, we’d be told to guess higher since 56.25 is lower than 60.
Because we have to guess higher, we know the square root of 60 has to be between 7.5 and 8, so we average those and plug in the new guess, like so:
>>> average(7.5, 8)
7.75
Now we check the square of 7.75 to see if it’s 60:
>>> 7.75**2
60.0625
Too high! So the square root must be between 7.5 and 7.75.
We can automate this process using the code in Listing 3-6. Open a new Python file and name it squareRoot.py.
squareRoot.py
def average(a,b):
return (a + b)/2
def squareRoot(num,low,high):
'''Finds the square root of num by
playing the Number Guessing Game
strategy by guessing over the
range from "low" to "high"'''
for i in range(20):
guess = average(low,high)
if guess**2 == num:
print(guess)
elif guess**2 > num: #"Guess lower."
high = guess
else: #"Guess higher."
low = guess
print(guess)
squareRoot(60,7,8)
Listing 3-6: Writing the squareRoot() function
Here, the squareRoot() function takes three parameters: num (the number we want the square root of), low (the lowest limit num can be), and high (the upper limit of num). If the number you guess squared is equal to num, we just print it and break out of the loop. This might happen for a whole number, but not for an irrational number. Remember, irrational numbers never end!
Next, the program checks whether the number you guess squared is greater than num, in which case you should guess lower. We shorten our range to go from low to the guess by replacing high with the guess. The only other possibility is if the guess is too low, in which case we shorten our range to go from the guess to high by replacing low with the guess.
The program keeps repeating that process as many times as we want (in this case, 20 times) and then prints the approximate square root. Keep in mind that any decimal, no matter how long, can only approximate an irrational number. But we can still get a very good approximation!
In the final line we call the squareRoot() function, giving it the number we want the square root of, and the low and high numbers in the range we know the square root has to be in. Our output should look like this:
7.745966911315918
We can find out how close our approximation is by squaring it:
>>> 7.745966911315918**2
60.00000339120106
That’s pretty close to 60! Isn’t it surprising that we can calculate an irrational number so accurately just by guessing and averaging?
In this chapter, you learned about some handy tools like arithmetic operators, lists, inputs, and Booleans, as well as a crucial programming concept called conditionals. The idea that we can get the computer to compare values and make choices for us automatically, instantly, and repeatedly is extremely powerful. Every programming language has a way to do this, and in Python we use if, elif, and else statements. As you’ll see throughout this book, you’ll build on these tools to tackle meatier tasks to explore math.
In the next chapter, you’ll practice the tools you learned so far to solve algebra problems quickly and efficiently. You’ll use the number-guessing strategy to solve complicated algebraic equations that have more than one solution! And you’ll write a graphing program so you can better estimate the solutions to equations and make your math explorations more visual!