A powerful calculator

Python prompt and Read-Eval-Print Loop (REPL)

Python is an interpreted language. We can collect sequences of commands into text files and save this to file as a Python program. It is convention that these files have the file extension “.py”, for example hello.py.

We can also enter individual commands at the Python prompt which are immediately evaluated and carried out by the Python interpreter. This is very useful for the programmer/learner to understand how to use certain commands (often before one puts these commands together in a longer Python program). Python’s role can be described as Reading the command, Evaluating it, Printing the evaluated value and repeating (Loop) the cycle – this is the origin of the REPL abbreviation.

Python comes with a basic terminal prompt; you may see examples from this with >>> marking the input:

>>> 2 + 2
4

We are using a more powerful REPL interface, the Jupyter Notebook. Blocks of code appear with an In prompt next to them:

In [1]:
4 + 5
Out[1]:
9

To edit the code, click inside the code area. You should get a green border around it. To run it, press Shift-Enter.

Calculator

Basic operations such as addition (+), subtraction (-), multiplication (*), division (/) and exponentiation (**) work (mostly) as expected:

In [2]:
10 + 10000
Out[2]:
10010
In [3]:
42 - 1.5
Out[3]:
40.5
In [4]:
47 * 11
Out[4]:
517
In [5]:
10 / 0.5
Out[5]:
20.0
In [6]:
2**2   # Exponentiation ('to the power of') is **, NOT ^
Out[6]:
4
In [7]:
2**3
Out[7]:
8
In [8]:
2**4
Out[8]:
16
In [9]:
2 + 2
Out[9]:
4
In [10]:
# This is a comment
2 + 2
Out[10]:
4
In [11]:
2 + 2  # and a comment on the same line as code
Out[11]:
4

and, using the fact that $\sqrt[n]{x} = x^{1/n}$, we can compute the $\sqrt{3} = 1.732050\dots$ using **:

In [12]:
3**0.5
Out[12]:
1.7320508075688772

Parenthesis can be used for grouping:

In [13]:
2 * 10 + 5
Out[13]:
25
In [14]:
2 * (10 + 5)
Out[14]:
30

Integer division

In Python 3, division works as you'd expect:

In [15]:
15/6
Out[15]:
2.5

In Python 2, however, 15/6 will give you 2.

This phenomenon is known (in many programming languages, including C) as integer division: because we provide two integer numbers (15 and 6) to the division operator (/), the assumption is that we seek a return value of type integer. The mathematically correct answer is (the floating point number) 2.5. (→ numerical data types in Chapter 13.)

The convention for integer division is to truncate the fractional digits and to return the integer part only (i.e. 2 in this example). It is also called “floor division”.

How to avoid integer division

There are two ways to avoid the problem of integer division:

  1. Use Python 3 style division: this is available even in Python 2 with a special import statement:

    >>> from __future__ import division
    >>> 15/6
    2.5
    

    If you want to use the from __future__ import division feature in a python program, it would normally be included at the beginning of the file.

  2. Alternatively, if we ensure that at least one number (numerator or denominator) is of type float (or complex), the division operator will return a floating point number. This can be done by writing 15. instead of 15, of by forcing conversion of the number to a float, i.e. use float(15) instead of 15:

    >>> 15./6
    2.5
    >>> float(15)/6
    2.5
    >>> 15/6.
    2.5
    >>> 15/float(6)
    2.5
    >>> 15./6.
    2.5
    

If we really want integer division, we can use //: 1//2 returns 0, in both Python 2 and 3.

Why should I care about this division problem?

Integer division can result in surprising bugs: suppose you are writing code to compute the mean value m = (x + y)/2 of two numbers x and y. The first attempt of writing this may read:

m = (x + y) / 2

Suppose this is tested with x = 0.5, y = 0.5, then the line above computes the correct answers m = 0.5 (because0.5 + 0.5 = 1.0, i.e. a 1.0 is a floating point number, and thus 1.0/2 evaluates to 0.5). Or we could use x = 10, y = 30, and because 10 + 30 = 40 and 40/2 evaluates to 20, we get the correct answer m = 20. However, if the integers x = 0 and y = 1 would come up, then the code returns m = 0 (because 0 + 1 = 1 and 1/2 evaluates to 0) whereas m = 0.5 would have been the right answer.

We have many possibilities to change the line of code above to work safely, including these three versions:

m = (x + y) / 2.0

m = float(x + y) / 2

m = (x + y) * 0.5

This integer division behaviour is common amongst most programming languages (including the important ones C, C++ and Fortran), and it is important to be aware of the issue.

Mathematical functions

Because Python is a general purpose programming language, commonly used mathematical functions such as sin, cos, exp, log and many others are located in the mathematics module with name math. We can make use of this as soon as we import the math module:

In [16]:
import math
math.exp(1.0)
Out[16]:
2.718281828459045

Using the dir function, we can see the directory of objects available in the math module:

In [17]:
dir(math)
Out[17]:
['__doc__',
 '__file__',
 '__loader__',
 '__name__',
 '__package__',
 '__spec__',
 'acos',
 'acosh',
 'asin',
 'asinh',
 'atan',
 'atan2',
 'atanh',
 'ceil',
 'copysign',
 'cos',
 'cosh',
 'degrees',
 'e',
 'erf',
 'erfc',
 'exp',
 'expm1',
 'fabs',
 'factorial',
 'floor',
 'fmod',
 'frexp',
 'fsum',
 'gamma',
 'hypot',
 'isfinite',
 'isinf',
 'isnan',
 'ldexp',
 'lgamma',
 'log',
 'log10',
 'log1p',
 'log2',
 'modf',
 'pi',
 'pow',
 'radians',
 'sin',
 'sinh',
 'sqrt',
 'tan',
 'tanh',
 'trunc']

As usual, the help function can provide more information about the module (help(math)) on individual objects:

In [18]:
help(math.exp)
Help on built-in function exp in module math:

exp(...)
    exp(x)
    
    Return e raised to the power of x.

The mathematics module defines to constants π and e:

In [19]:
math.pi
Out[19]:
3.141592653589793
In [20]:
math.e
Out[20]:
2.718281828459045
In [21]:
math.cos(math.pi)
Out[21]:
-1.0
In [22]:
math.log(math.e)
Out[22]:
1.0

Variables

A variable can be used to store a certain value or object. In Python, all numbers (and everything else, including functions, modules and files) are objects. A variable is created through assignement:

In [23]:
x = 0.5

Once the variable x has been created through assignment of 0.5 in this example, we can make use of it:

In [24]:
x*3
Out[24]:
1.5
In [25]:
x**2
Out[25]:
0.25
In [26]:
y = 111
y + 222
Out[26]:
333

A variable is overriden if a new value is assigned:

In [27]:
y = 0.7
math.sin(y) ** 2 + math.cos(y) ** 2
Out[27]:
1.0

The equal sign (’=’) is used to assign a value to a variable.

In [28]:
width = 20
height = 5 * 9
width * height
Out[28]:
900

A value can be assigned to several variables simultaneously:

In [29]:
x = y = z = 0  # initialise x, y and z with 0
x
Out[29]:
0
In [30]:
y
Out[30]:
0
In [31]:
z
Out[31]:
0

Variables must be created (assigned a value) before they can be used, or an error will occur:

In [32]:
# try to access an undefined variable
n
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-32-0f97ef769cd5> in <module>()
      1 # try to access an undefined variable
----> 2 n

NameError: name 'n' is not defined

In interactive mode, the last printed expression is assigned to the variable _. This means that when you are using Python as a desk calculator, it is somewhat easier to continue calculations, for example:

In [33]:
tax = 12.5 / 100
price = 100.50
price * tax
Out[33]:
12.5625
In [34]:
price + _
Out[34]:
113.0625

This variable should be treated as read-only by the user. Don’t explicitly assign a value to it — you would create an independent local variable with the same name masking the built-in variable with its magic behavior.

Terminology

Strictly speaking, the following happens when we write

In [35]:
x = 0.5

First, Python creates the object 0.5. Everything in Python is an object, and so is the floating point number 0.5. This object is stored somewhere in memory. Next, Python binds a name to the object. The name is x, and we often refer casually to x as a variable, an object, or even the value 0.5. However, technically, x is a name that is bound to the object 0.5. Another way to say this is that x is a reference to the object.

While it is often sufficient to think about assigning 0.5 to a variable x, there are situations where we need to remember what actually happens. In particular, when we pass references to objects to functions, we need to realise that the function may operate on the object (rather than a copy of the object). This is discussed in more detail in the next chapter.

Impossible equations

In computer programs we often find statements like

In [36]:
x = x + 1

If we read this as an equation as we are use to from mathematics, x = x + 1 we could subtract x on both sides, to find that 0 = 1. We know this is not true, so something is wrong here.

The answer is that “equations“ in computer codes are not equations but assignments. They always have to be read in the following way two-step way:

  1. Evaluate the value on the right hand side of the equal sign

  2. Assign this value to the variable name shown on the left hand side. (In Python: bind the name on the left hand side to the object shown on the right hand side.)

Some computer science literature uses the following notation to express assignments and to avoid the confusion with mathematical equations:

$$x \leftarrow x + 1$$

Let’s apply our two-step rule to the assignment x = x + 1 given above:

  1. Evaluate the value on the right hand side of the equal sign: for this we need to know what the current value of x is. Let’s assume x is currently 4. In that case, the right hand side x+1 evaluates to 5.

  2. Assign this value (i.e. 5) to the variable name shown on the left hand side x.

Let’s confirm with the Python prompt that this is the correct interpretation:

In [37]:
x = 4     
x = x + 1
x
Out[37]:
5

The += notation

Because it is a quite a common operation to increase a variable x by some fixed amount c, we can write

x += c

instead of

x = x + c

Our initial example above could thus have been written

In [38]:
x = 4
x += 1
x
Out[38]:
5

The same operators are defined for multiplication with a constant (*=), subtraction of a constant (-=) and division by a constant (/=).

Note that the order of + and = matters:

In [39]:
x += 1

will increase the variable x by one where as

In [40]:
x =+ 1

will assign the value +1 to the variable x.