This chapter is taken from the book A Primer on Scientific Programming with Python by H. P. Langtangen, 5th edition, Springer, 2016.
Our task now is to print out a conversion table with Celsius degrees in the first column of the table and the corresponding Fahrenheit degrees in the second column. Such a table may look like this:
-20 -4.0
-15 5.0
-10 14.0
-5 23.0
0 32.0
5 41.0
10 50.0
15 59.0
20 68.0
25 77.0
30 86.0
35 95.0
40 104.0
The formula for converting \( C \) degrees Celsius to \( F \) degrees Fahrenheit is \( F=9C/5 + 32 \). Since we know how to evaluate the formula for one value of \( C \), we can just repeat these statements as many times as required for the table above. Using three statements per line in the program, for compact layout of the code, we can write the whole program as
C = -20; F = 9.0/5*C + 32; print C, F
C = -15; F = 9.0/5*C + 32; print C, F
C = -10; F = 9.0/5*C + 32; print C, F
C = -5; F = 9.0/5*C + 32; print C, F
C = 0; F = 9.0/5*C + 32; print C, F
C = 5; F = 9.0/5*C + 32; print C, F
C = 10; F = 9.0/5*C + 32; print C, F
C = 15; F = 9.0/5*C + 32; print C, F
C = 20; F = 9.0/5*C + 32; print C, F
C = 25; F = 9.0/5*C + 32; print C, F
C = 30; F = 9.0/5*C + 32; print C, F
C = 35; F = 9.0/5*C + 32; print C, F
C = 40; F = 9.0/5*C + 32; print C, F
Running this program (which is stored in the file
c2f_table_repeat.py
),
demonstrates that the output becomes
-20 -4.0
-15 5.0
-10 14.0
-5 23.0
0 32.0
5 41.0
10 50.0
15 59.0
20 68.0
25 77.0
30 86.0
35 95.0
40 104.0
This output suffers from somewhat ugly formatting, but that problem
can quickly
be fixed by replacing print C, F
by a print
statement based
on printf formatting. We will return to this detail later.
The main problem with the program above is that lots of statements are
identical and repeated. First of all it is boring to write this sort
of repeated statements, especially if we want many more \( C \) and \( F \)
values in the table. Second, the idea of the computer
is to automate repetition. Therefore, all computer languages have
constructs to efficiently express repetition. These constructs are called
loops and come in two variants in Python:
while
loops and for
loops. Most programs in this document
employ loops, so this concept is extremely important to learn.
The while
loop is used to repeat a set of statements as long as a
condition is true. We shall introduce this kind of loop through an
example. The task is to generate the rows of the table of \( C \) and \( F \)
values. The \( C \) value starts at \( -20 \) and is incremented by 5 as long
as \( C\leq 40 \). For each \( C \) value we compute the corresponding \( F \)
value and write out the two temperatures. In addition, we also add a
line of dashes above and below the table.
The list of tasks to be done can be summarized as follows:
print '------------------' # table heading
C = -20 # start value for C
dC = 5 # increment of C in loop
while C <= 40: # loop heading with condition
F = (9.0/5)*C + 32 # 1st statement inside loop
print C, F # 2nd statement inside loop
C = C + dC # 3rd statement inside loop
print '------------------' # end of table line (after loop)
A very important feature of Python is now encountered: the block of
statements to be executed in each pass of the while
loop must be
indented. In the example above the block consists of three lines, and
all these lines must have exactly the same indentation. Our choice of
indentation in this document is four spaces. The first statement whose
indentation coincides with that of the while
line marks the end of
the loop and is executed after the loop has terminated. In this
example this is the final print
statement. You are encouraged to
type in the code above in a file, indent the last line four spaces,
and observe what happens (you will experience that lines in the table
are separated by a line of dashes: --------
).
Many novice Python programmers forget the colon at the end of the
while
line - this colon is essential and marks the beginning of the
indented block of statements inside the loop. Later, we will see that
there are many other similar program constructions in Python where
there is a heading ending with a colon, followed by an indented block
of statements.
Programmers need to fully understand what is going on in a program and
be able to simulate the program by hand. Let us do this with the
program segment above. First, we define the start value for the
sequence of Celsius temperatures: C = -20
. We also define the
increment dC
that will be added to C
inside the loop. Then we
enter the loop condition C <= 40
. The first time C
is -20
,
which implies that C <= 40
(equivalent to \( C\leq 40 \) in mathematical
notation) is true. Since the loop condition is true, we enter the
loop and execute all the indented statements. That is, we compute F
corresponding to the current C
value, print the temperatures, and
increment C
by dC
. For simplicity, we have used
a plain print C, F
without any formatting so the columns will not
be aligned, but this can easily be fixed later.
Thereafter, we enter the second pass in the loop. First we check the
condition: C
is -15
and C <= 40
is still true. We execute the
statements in the indented loop block, C
becomes -10
, this is
still less than or equal to 40
, so we enter the loop block
again. This procedure is repeated until C
is updated from 40
to
45
in the final statement in the loop block. When we then test the
condition, C <= 40
, this condition is no longer true, and the loop
is terminated. We proceed with the next statement that has the same
indentation as the while
statement, which is the final print
statement in this example.
Newcomers to programming are sometimes confused by statements like
C = C + dC
This line looks erroneous from a mathematical viewpoint, but the
statement is perfectly valid computer code, because we first evaluate
the expression on the right-hand side of the equality sign and then
let the variable on the left-hand side refer to the result of this
evaluation. In our case, C
and dC
are two different int
objects. The operation C+dC
results in a new int
object, which in
the assignment C = C+dC
is bound to the name C
. Before this
assignment, C
was already bound to an int
object, and this object
is automatically destroyed when C
is bound to a new object and there
are no other names (variables) referring to this previous object (if
you did not get this last point, just relax and continue reading!).
Since incrementing the value of a variable is frequently done in computer programs, there is a special short-hand notation for this and related operations:
C += dC # equivalent to C = C + dC
C -= dC # equivalent to C = C - dC
C *= dC # equivalent to C = C*dC
C /= dC # equivalent to C = C/dC
In our first example on a while
loop, we worked with a condition
C <= 40
, which evaluates to either true or false, written as
True
or False
in Python.
Other comparisons are also useful:
C == 40 # C equals 40
C != 40 # C does not equal 40
C >= 40 # C is greater than or equal to 40
C > 40 # C is greater than 40
C < 40 # C is less than 40
Not only comparisons between numbers
can be used as conditions in while
loops: any
expression that has a boolean (True
or False
) value can be used.
Such expressions are known as logical or boolean
expressions.
The keyword not
can be inserted in front of the boolean
expression to change the value from True
to False
or from
False
to True
.
To evaluate not C == 40
, we first evaluate C == 40
,
for C = 1
this is False
, and then not
turns the value into
True
. On
the opposite, if C == 40
is True
, not C == 40
becomes
False
. Mathematically it is easier to read C != 40
than
not C == 40
, but these two boolean expressions are equivalent.
Boolean expressions can be combined with and
and or
to
form new compound boolean expressions, as in
while x > 0 and y <= 1:
print x, y
If cond1
and cond2
are two boolean expressions with values
True
or False
,
the compound boolean expression cond1 and cond2
is True
if both cond1
and cond2
are True
.
On the other hand, cond1 or cond2
is True
if at
least one of the conditions, cond1
or cond2
, is True
In Python,
cond1 and cond2
or cond1 or cond2
returns one of the operands
and not just True
or False
values as in most other
computer languages. The operands cond1
or cond2
can be expressions or objects. In case of expressions, these are first
evaluated
to an object before the compound boolean expression is evaluated.
For example, (5+1) or -1
evaluates to
6
(the second operand is not evaluated when the first one is
True
), and (5+1) and -1
evaluates to -1
.
Here are some more examples from an interactive session where we just evaluate the boolean expressions themselves without using them in loop conditions:
>>> x = 0; y = 1.2
>>> x >= 0 and y < 1
False
>>> x >= 0 or y < 1
True
>>> x > 0 or y > 1
True
>>> x > 0 or not y > 1
False
>>> -1 < x <= 0 # -1 < x and x <= 0
True
>>> not (x > 0 or y > 0)
False
In the last sample expression, not
applies to the value of the
boolean expression inside the parentheses: x>0
is False
, y>0
is True
, so the combined expression with or
is True
,
and not
turns this value to False
.
The common
boolean values in Python are True
, False
, 0
(false),
and any integer different from zero (true). To see such values in
action, we recommend doing
Exercise 22: Interpret a code and
Exercise 18: Values of boolean expressions.
All objects in Python can in fact be evaluated in a
boolean context, and all are True
except False
, zero numbers,
and empty strings, lists, and dictionaries:
>>> s = 'some string'
>>> bool(s)
True
>>> s = '' # empty string
>>> bool(s)
False
>>> L = [1, 4, 6]
>>> bool(L)
True
>>> L = []
>>> bool(L)
False
>>> a = 88.0
>>> bool(a)
True
>>> a = 0.0
>>> bool(a)
False
Essentially, if a
tests if a
is a non-empty object or if it is
non-zero value. Such constructions are frequent in Python code.
Erroneous thinking about boolean expressions is one of the most common sources of errors in computer programs, so you should be careful every time you encounter a boolean expression and check that it is correctly stated.
Summations frequently appear in mathematics. For instance,
the sine function can be calculated as a polynomial:
$$
\begin{equation}
\sin (x) \approx x - \frac{x^3}{3!} + \frac{x^5}{5!} - \frac{x^7}{7!} +
\cdots,
\tag{1}
\end{equation}
$$
where \( 3!=3\cdot 2\cdot 1 \), \( 5! = 5\cdot 4\cdot 3\cdot 2\cdot 1 \),
etc., are factorial expressions. Computing \( k!=k(k-1)(k-2)\cdots 2\cdot 1 \)
is done by math.factorial(k)
.
An infinite number of terms are needed on the right-hand side of (1) for the equality sign to hold. With a finite number of terms, we obtain an approximation to \( \sin (x) \), which is well suited for being calculated in a program since only powers and the basic four arithmetic operations are involved. Say we want to compute the right-hand side of (1) for powers up to \( N=25 \). Writing out and implementing each one of these terms is a tedious job that can easily be automated by a loop.
Computation of the sum in (1) by a while
loop in
Python, makes use of (i) a counter k
that runs through odd
numbers from 1 up to some given maximum power N
, and (ii) a
summation variable, say s
, which accumulates the terms, one at a
time. The purpose of each pass of the loop is to compute a new term
and add it to s
. Since the sign of each term alternates, we introduce
a variable sign
that changes between \( -1 \) and \( 1 \) in each pass
of the loop.
The previous paragraph can be precisely expressed by this piece of Python code:
x = 1.2 # assign some value
N = 25 # maximum power in sum
k = 1
s = x
sign = 1.0
import math
while k < N:
sign = - sign
k = k + 2
term = sign*x**k/math.factorial(k)
s = s + term
print 'sin(%g) = %g (approximation with %d terms)' % (x, s, N)
The best way to understand such a program is to simulate it by
hand. That is, we go through the statements, one by one, and write down
on a piece of paper what the state of each variable is.
When the loop is first entered, k < N
implies 1 < 25
,
which is True
so we enter the loop block. There, we compute
sign = -1.0
, k = 3
, term = -1.0*x**3/(3*2*1))
(note that sign
is float so we always have float
divided
by int
),
and s = x - x**3/6
, which equals the first two terms in the
sum. Then we test the loop condition: 3 < 25
is True
so
we enter the loop block again. This time we obtain
term = 1.0*x**5/math.factorial(5)
, which correctly implements
the third term in the sum. At some point, k
is updated to
from 23
to 25
inside the loop and the loop condition
then becomes 25 < 25
, which is False
, implying that the
program jumps over the loop block and continues with the print
statement (which has the same indentation as the while
statement).