Programming 1, 2020-1
Lecture 2: Notes

Much of the material from this week's lecture is covered in these sections of Think Python:

And in these chapters of Introducing Python:

Here are some additional notes.

Removing all zeroes

This program uses a while loop to remove all zeroes at the end of a decimal number:

n = int(input('Enter n: '))

if n != 0:
  while n % 10 == 0:
    n = n // 10

print(n)

Nested loops

In programming it is common to use a nested loop, i.e. a loop inside a loop. For example, here's a program that prints out a rectangle of asterisks:

x = int(input('Enter x: '))
y = int(input('Enter y: '))


for i in range(y):
  for j in range(x):
    print('*', end = '')  # print '*' and stay on the same line
  print('')   # move to the next line

The output looks like this:

Enter x: 7
Enter y: 3
*******
*******
*******

Note that the inner loop ("for j in range(x)") runs in its entirety on every iteration of the outer loop ("for i in range(y)"). So the total number of asterisks printed is x ⋅ y.

We can also change the bounds of the inner loop on each iteration of the outer loop. For example, here is a program to print a triangle of asterisks:

n = int(input('Enter size: '))
  
for i in range(1, n + 1):
  for j in range(i):
    print('*', end = '')
  print('')

The output looks like this:

Enter size: 5
*
**
***
****
*****

In each of these examples we've used a doubly nested loop, i.e. a loop inside a loop. Of course, loops may be triply or even arbitrarily nested.

Math functions

For our first peek into Python's enormous standard library, we will see how to use Python's built-in math functions. To get access to these, write this at the top of your program:

import math

These functions include

and many others. Our Python Library Quick Reference lists these functions and others. Also, you can see a full list in the Python library documentation.

To use any of these functions, write "math." followed by the name of the function. For example:

import math

print(math.sqrt(2))

prints

1.4142135623730951

A number-guessing game

We now have the tools we need to write a simple game. In this game, the computer chooses a random number between 1 and 1000 and the user has to guess it:

I am thinking of a number from 1 to 1000.
Your guess? 800 
Too low!
Your guess? 900
Too high:
Your guess? 850
Too low:
Your guess? 860
Too high:
Your guess? 864
You got it!

Here is the program:

import random

print('I am thinking of a number from 1 to 1000.')
n = random.randint(1, 1000)
while True:
  g = int(input('Your guess? '))
  if g == n:
    break
  if g < n:
    print('Too low!')
  else:
    print('Too high!')
    
print('You got it!')

If we are the user playing this game, what is our best strategy to minimize the number of guesses we may need to make? And how many guesses might be required?

As we play the game, at every moment we know that the target number falls in the range A...B for some integers A and B. As you might imagine, our best strategy is as follows. At each step, we guess a number G that divides this interval in half, i.e. G = (A + B) // 2. If G is too high, then we now know that the target number is in the range A … (G – 1). If it is too low, we now know that it's in the range (G + 1) … B.

This guessing strategy is called a binary search, which is actually an important algorithm that we'll see again later in this course. With this strategy, at each step the size of the interval containing the target value drops by a factor of 2. So after K guesses its size has dropped by a factor of 2K. In particular, in this case the interval originally contains 1000 numbers. After the first guess, its size is at most 1000 / 2 = 500. After the second guess, its size is at most 1000 / 22 = 250. And so on. After 10 guesses, the interval has dropped by a factor of 210 = 1024, and must now contain only a single number. In other words, 10 guesses are always sufficient to determine the number that the computer has chosen.

In general, if the computer chooses a random number from 1 to N then we might need log2(N) guesses in the worst case.

Standard input

On all major operating systems, as a program runs it can read from its standard input. (Usually standard input comes from the terminal, but it is also possible to redirect it to come from a file instead.)

In Python, we will often want to read lines from standard input. Fortunately this is easy. The sys.stdin object is a sequence of lines, and so we can loop over it using for. For example, here is a program that reads numbers from standard input, one per line, and computes their sum:

import sys
  
sum = 0
for line in sys.stdin:
  n = int(line)    # convert string to integer
  sum += n
  
print('The sum is', sum)

When we run the program and enter its input from a terminal, we need some way to signal that the input is complete. On Linux or macOS, we can do this by typing Ctrl+D. On Windows, type Ctrl+Z followed by Enter.

When we run the program, we see this:

3
4
5
The sum is 12

Above, we typed Ctrl+D or Ctrl+Z after the number 5 (though that was not visible in the terminal output).

Tutorial programs

Here are the programs that we wrote together in the tutorial.

1. Numbers from 2 to 20

Print the even numbers from 2 to 20 on the console.

for n in range(2, 22, 2):
    print(n)

2. Factorial

Write a program that reads a number N ≥ 0 and prints the value of N!, i.e. 1 ⋅ 2 ⋅ … ⋅ N.

n = int(input('Enter N: '))

p = 1
for k in range(1, n + 1):
    p *= k

print(str(n) + '! = ' + str(p))

4. All Divisors

Write a program that reads a positive integer N and prints all of its divisors, as well as a count of the divisors.

n = int(input('Enter N: '))

count = 0
for d in range(1, n + 1):
    if n % d == 0:
        print(d)
        count += 1

print('There are', count, 'divisors')

6. Square

Read a number N, then print an N x N square of asterisks.

n = int(input('Enter N: '))

print(n * '*')

for i in range(n - 2):
    print('*' + (n - 2) * ' ' + '*')

print(n * '*')

7. Triangle

Read a number N, then print an N x N triangle of asterisks.

n = int(input('Enter N: '))

for k in range(1, n + 1):
    print((n - k) * ' ' + k * '*')

12. Power of Two

Read an integer. Print "pow" if it is a power of 2, "no" otherwise. (Note: 1 is actually a power of 2, since 20 = 1).

n = int(input('Enter number: '))

while n > 1:
    if n % 2 > 0:   # n is odd
        break       # not a power of two
        n = n // 2

if n == 1:
    print('pow')
else:
    print('no')

14. Second Largest

Write a program that reads a series of non-negative integers from standard input until the user presses Ctrl+D or Ctrl+Z. The program should then print the second largest of the integers that were read.

import sys

largest = -1
second_largest = -1

for line in sys.stdin:
    n = int(line)
    if n > largest:
        largest, second_largest = n, largest
    elif n > second_largest:
        second_largest = n

print(second_largest)

20. Multiples of 3 and 5

Find the sum of all the multiples of 3 or 5 below 1000.

sum = 0

for n in range(1000):
    if n % 3 == 0 or n % 5 == 0:
        sum += n

print(sum)

21. Even Fibonacci numbers

Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.

a, b = 1, 2

sum = 0

while a < 4000000:
    if a % 2 == 0:
        sum += a
    a, b = b, a + b

print(sum)