$$ \newcommand{\tp}{\thinspace .} $$

This chapter is taken from the book A Primer on Scientific Programming with Python by H. P. Langtangen, 5th edition, Springer, 2016.

Exercises

Exercise 1: Make a Fahrenheit-Celsius conversion table

Write a Python program that prints out a table with Fahrenheit degrees \( 0, 10, 20, \ldots, 100 \) in the first column and the corresponding Celsius degrees in the second column.

Hint. Modify the c2f_table_while.py program from the section While loops.

Filename: f2c_table_while.

Exercise 2: Generate an approximate Fahrenheit-Celsius conversion table

Many people use an approximate formula for quickly converting Fahrenheit (\( F \)) to Celsius (\( C \)) degrees: $$ \begin{equation} C \approx \hat C = (F-30)/2 \tag{2} \end{equation} $$ Modify the program from Exercise 1: Make a Fahrenheit-Celsius conversion table so that it prints three columns: \( F \), \( C \), and the approximate value \( \hat C \). Filename: f2c_approx_table.

Exercise 3: Work with a list

Set a variable primes to a list containing the numbers 2, 3, 5, 7, 11, and 13. Write out each list element in a for loop. Assign 17 to a variable p and add p to the end of the list. Print out the entire new list. Filename: primes.

Exercise 4: Generate odd numbers

Write a program that generates all odd numbers from 1 to n. Set n in the beginning of the program and use a while loop to compute the numbers. (Make sure that if n is an even number, the largest generated odd number is n-1.) Filename: odd.

Exercise 5: Compute the sum of the first \( n \) integers

Write a program that computes the sum of the integers from 1 up to and including \( n \). Compare the result with the famous formula \( n(n+1)/2 \). Filename: sum_int.

Exercise 6: Compute energy levels in an atom

The \( n \)-th energy level for an electron in a Hydrogen atom is given by $$ E_n = -\frac{m_e e^4}{8\epsilon_0^2h^2}\cdot\frac{1}{n^2} , $$ where \( m_e = 9.1094\cdot 10^{-31} \) kg is the electron mass, \( e = 1.6022\cdot 10^{-19} \) C is the elementary charge, \( \epsilon_0 = 8.8542\cdot 10^{-12} \) C$^2$s$^2$ kg$^{-1}$ m$^-3$ is the electrical permittivity of vacuum, and \( h = 6.6261\cdot 10^{-34} \) Js.

a) Write a Python program that calculates and prints the energy level \( E_n \) for \( n=1,\ldots , 20 \).

b) The released energy when an electron moves from level \( n_i \) to level \( n_f \) is given by $$ \Delta E = -\frac{m_e e^4}{8\epsilon_0^2h^2}\cdot\left( \frac{1}{n_i^2}-\frac{1}{n_f^2}\right) \tp $$ Add statements to the program from a) so that it prints a second, nicely formatted table where the cell in column \( i \) and row \( f \) contains the energy released when an electron moves from energy level \( i \) to level \( f \), for \( i,f = 1,\ldots , 5 \).

Filename: energy_levels.

Exercise 7: Generate equally spaced coordinates

We want to generate \( n+1 \) equally spaced \( x \) coordinates in \( [a,b] \). Store the coordinates in a list.

a) Start with an empty list, use a for loop and append each coordinate to the list.

Hint. With \( n \) intervals, corresponding to \( n+1 \) points, in \( [a,b] \), each interval has length \( h=(b-a)/n \). The coordinates can then be generated by the formula \( x_i=a+ih \), \( i=0,\ldots,n+1 \).

b) Use a list comprehension as an alternative implementation.

Filename: coor.

Exercise 8: Make a table of values from a formula

The purpose of this exercise is to write code that prints a nicely formatted table of \( t \) and \( y(t) \) values, where $$ \begin{equation*} y(t) = v_0t - \frac{1}{2}gt^2\tp\end{equation*} $$ Use \( n+1 \) uniformly spaced \( t \) values throughout the interval \( [0, 2v_0/g] \).

a) Use a for loop to produce the table.

b) Add code with a while loop to produce the table.

Hint. Because of potential round-off errors, you may need to adjust the upper limit of the while loop to ensure that the last point (\( t=2v_0/g \), \( y=0 \)) is included.

Filename: ball_table1.

Exercise 9: Store values from a formula in lists

This exercise aims to produce the same table of numbers as in Exercise 8: Make a table of values from a formula, but with different code. First, store the \( t \) and \( y \) values in two lists t and y. Thereafter, write out a nicely formatted table by traversing the two lists with a for loop.

Hint. In the for loop, use either zip to traverse the two lists in parallel, or use an index and the range construction.

Filename: ball_table2.

Exercise 10: Simulate operations on lists by hand

You are given the following program:

a = [1, 3, 5, 7, 11]
b = [13, 17]
c = a + b
print c
b[0] = -1
d = [e+1 for e in a]
print d
d.append(b[0] + 1)
d.append(b[-1] + 1)
print d[-2:]
for e1 in a:
    for e2 in b:
        print e1 + e2
Go through each statement and explain what is printed by the program. Filename: simulate_lists.

Exercise 11: Compute a mathematical sum

The following code is supposed to compute the sum \( s = \sum_{k=1}^M {1\over k} \):

s = 0;  k = 1;  M = 100
while k < M:
    s += 1/k
print s
This program does not work correctly. What are the three errors? (If you try to run the program, nothing will happen on the screen. Type Ctrl+c, i.e., hold down the Control (Ctrl) key and then type the c key, to stop the program.) Write a correct program.

Hint. There are two basic ways to find errors in a program:

  1. read the program carefully and think about the consequences of each statement,
  2. print out intermediate results and compare with hand calculations.
First, try method 1 and find as many errors as you can. Thereafter, try method 2 for \( M=3 \) and compare the evolution of s with your own hand calculations.

Filename: sum_while.

Exercise 12: Replace a while loop by a for loop

Rewrite the corrected version of the program in Exercise 11: Compute a mathematical sum using a for loop over k values instead of a while loop. Filename: sum_for.

Exercise 13: Simulate a program by hand

Consider the following program for computing with interest rates:

initial_amount = 100
p = 5.5  # interest rate
amount = initial_amount
years = 0
while amount <= 1.5*initial_amount:
    amount = amount + p/100*amount
    years = years + 1
print years

a) Use a pocket calculator or an interactive Python shell and work through the program calculations by hand. Write down the value of amount and years in each pass of the loop.

b) Set p = 5 instead. Why will the loop now run forever? (Apply Ctrl+c, see Exercise 11: Compute a mathematical sum, to stop a program with a loop that runs forever.) Make the program robust against such errors.

c) Make use of the operator += wherever possible in the program.

d) Explain with words what type of mathematical problem that is solved by this program.

Filename: interest_rate_loop.

Exercise 14: Explore Python documentation

Suppose you want to compute with the inverse sine function: \( \sin^{-1}x \). How do you do that in a Python program?

Hint. The math module has an inverse sine function. Find the correct name of the function by looking up the module content in the online Python Standard Library document or use pydoc, see the section How to find more Python information.

Filename: inverse_sine.

Exercise 15: Index a nested list

We define the following nested list:

q = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h']]

a) Index this list to extract 1) the letter a; 2) the list ['d', 'e', 'f']; 3) the last element h; 4) the d element. Explain why q[-1][-2] has the value g.

b) We can visit all elements of q using this nested for loop:

for i in q:
    for j in range(len(i)):
        print i[j]
What type of objects are i and j?

Filename: index_nested_list.

Exercise 16: Store data in lists

Modify the program from Exercise 2: Generate an approximate Fahrenheit-Celsius conversion table so that all the \( F \), \( C \), and \( \hat C \) values are stored in separate lists F, C, and C_approx, respectively. Then make a nested list conversion so that conversion[i] holds a row in the table: [F[i], C[i], C_approx[i]]. Finally, let the program traverse the conversion list and write out the same table as in Exercise 2: Generate an approximate Fahrenheit-Celsius conversion table. Filename: f2c_approx_lists.

Exercise 17: Store data in a nested list

The purpose of this exercise is to store tabular data in two alternative ways, either as a list of columns or as a list of rows. In order to write out a nicely formatted table, one has to traverse the data, and the technique for traversal depends on how the tabular data is stored.

a) Compute two lists of \( t \) and \( y \) values as explained in Exercise 9: Store values from a formula in lists. Store the two lists in a new nested list ty1 such that ty1[0] and ty1[1] correspond to the two lists. Write out a table with \( t \) and \( y \) values in two columns by looping over the data in the ty1 list. Each number should be written with two decimals.

b) Make a list ty2 which holds each row in the table of \( t \) and \( y \) values (ty1 is a list of table columns while ty2 is a list of table rows, as explained in the section Nested lists). Loop over the ty2 list and write out the \( t \) and \( y \) values with two decimals each.

Filename: ball_table3.

Exercise 18: Values of boolean expressions

Explain the outcome of each of the following boolean expressions:

C = 41
C == 40
C != 40 and C < 41
C != 40 or  C < 41
not C == 40
not C > 40
C <= 41
not False
True and False
False or True
False or False or False
True and True and False
False == 0
True == 0
True == 1

Note.

It makes sense to compare True and False to the integers 0 and 1, but not other integers (e.g., True == 12 is False although the integer 12 evaluates to True in a boolean context, as in bool(12) or if 12).

Filename: eval_bool.

Exercise 19: Explore round-off errors from a large number of inverse operations

Maybe you have tried to hit the square root key on a calculator multiple times and then squared the number again an equal number of times. These set of inverse mathematical operations should of course bring you back to the starting value for the computations, but this does not always happen. To avoid tedious pressing of calculator keys, we can let a computer automate the process. Here is an appropriate program:

from math import sqrt
for n in range(1, 60):
    r = 2.0
    for i in range(n):
        r = sqrt(r)
    for i in range(n):
        r = r**2
    print '%d times sqrt and **2: %.16f' % (n, r)
Explain with words what the program does. Then run the program. Round-off errors are here completely destroying the calculations when n is large enough! Investigate the case when we come back to 1 instead of 2 by fixing an n value where this happens and printing out r in both for loops over i. Can you now explain why we come back to 1 and not 2? Filename: repeated_sqrt.

Exercise 20: Explore what zero can be on a computer

Type in the following code and run it:

eps = 1.0
while 1.0 != 1.0 + eps:
    print '...............', eps
    eps = eps/2.0
print 'final eps:', eps
Explain with words what the code is doing, line by line. Then examine the output. How can it be that the "equation" \( 1\neq 1+ \hbox{eps} \) is not true? Or in other words, that a number of approximately size \( 10^{-16} \) (the final eps value when the loop terminates) gives the same result as if eps were zero? Filename: machine_zero.

Remarks

The nonzero eps value computed above is called machine epsilon or machine zero and is an important parameter to know, especially when certain mathematical techniques are applied to control round-off errors.

Exercise 21: Compare two real numbers with a tolerance

Run the following program:

a = 1/947.0*947
b = 1
if a != b:
    print 'Wrong result!'

The lesson learned from this program is that one should never compare two floating-point objects directly using a == b or a != b, because round-off errors quickly make two identical mathematical values different on a computer. A better result is to test if abs(a - b) < tol, where tol is a very small number. Modify the test according to this idea. Filename: compare_floats.

Exercise 22: Interpret a code

The function time in the module time returns the number of seconds since a particular date (called the Epoch, which is January 1, 1970, on many types of computers). Python programs can therefore use time.time() to mimic a stop watch. Another function, time.sleep(n) causes the program to pause for n seconds and is handy for inserting a pause. Use this information to explain what the following code does:

import time
t0 = time.time()
while time.time() - t0 < 10:
    print '....I like while loops!'
    time.sleep(2)
print 'Oh, no - the loop is over.'
How many times is the print statement inside the loop executed? Now, copy the code segment and change the < sign in the loop condition to a > sign. Explain what happens now. Filename: time_while.

Exercise 23: Explore problems with inaccurate indentation

Type in the following program in a file and check carefully that you have exactly the same spaces:

C = -60; dC = 2
while C <= 60:
    F = (9.0/5)*C + 32
      print C, F
C = C + dC
Run the program. What is the first problem? Correct that error. What is the next problem? What is the cause of that problem? (See Exercise 11: Compute a mathematical sum for how to stop a hanging program.) Filename: indentation.

Remarks

The lesson learned from this exercise is that one has to be very careful with indentation in Python programs! Other computer languages usually enclose blocks belonging to loops in curly braces, parentheses, or begin-end marks. Python's convention with using solely indentation contributes to visually attractive, easy-to-read code, at the cost of requiring a pedantic attitude to blanks from the programmer.

Exercise 24: Explore punctuation in Python programs

Some of the following assignments work and some do not. Explain in each case why the assignment works/fails and, if it works, what kind of object x refers to and what the value is if we do a print x.

x = 1
x = 1.
x = 1;
x = 1!
x = 1?
x = 1:
x = 1,

Hint. Explore the statements in an interactive Python shell.

Filename: punctuation.

Exercise 25: Investigate a for loop over a changing list

Study the following interactive session and explain in detail what happens in each pass of the loop, and use this explanation to understand the output.

>>> numbers = range(10)
>>> print numbers
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> for n in numbers:
...     i = len(numbers)/2
...     del numbers[i]
...     print 'n=%d, del %d' % (n,i), numbers
...
n=0, del 5 [0, 1, 2, 3, 4, 6, 7, 8, 9]
n=1, del 4 [0, 1, 2, 3, 6, 7, 8, 9]
n=2, del 4 [0, 1, 2, 3, 7, 8, 9]
n=3, del 3 [0, 1, 2, 7, 8, 9]
n=8, del 3 [0, 1, 2, 8, 9]

Warning.

The message in this exercise is to never modify a list that we are looping over. Modification is indeed technically possible, as shown above, but you really need to know what you are doing. Otherwise you will experience very strange program behavior.

Filename: for_changing_list.

References

  1. P. S. Foundation. The Python Standard Library, \urlhttp://docs.python.org/2/library/, http://docs.python.org/2/library/.
  2. D. Beazley. Python Essential Reference, 4th edition, Addison-Wesley, 2009.
  3. M. Lutz. Learning Python, O'Reilly, 2013.
  4. C. F\"uhrer, J. E. Solem and O. Verdier. Computing with Python - An Introduction to Python for Science and Engineering, Pearson, 2014.
  5. H. P. Langtangen. Python Scripting for Computational Science, 3rd edition, Texts in Computational Science and Engineering, Springer, 2009.
  6. R. Gruet. Python Quick Reference, \urlhttp://rgruet.free.fr/, http://rgruet.free.fr/.