Boolean algebra, conditional statements, loops.
by Eugeniy E. Mikhailov and Greg Bentsen
Suppose a bank gives you a 50% interest rate (let’s call it ‘x’), and you put one dollar in.
How much would you get at the end of the year?
Now let’s find how your return on investment () depends on the number of payments per year
import numpy as np
Nmax = 1000
M = np.zeros(Nmax) # we need to preallocate space
x=0.5
allN = range(1, Nmax+1)
for N in allN:
M[N-1] = np.pow(1+x/N, N) # position in array starts from 0!
import matplotlib.pyplot as plt
plt.plot(allN, M, '.-')
plt.grid(True)
plt.xlabel("N, number of payments per year")
plt.ylabel("$M_N$, return on investment") # Note it understands LaTeX!
plt.title("Return on investment vs number of payments")
plt.savefig("return_on_investment.png")
Of course we do not need a computer to show that but we need it to calculate something like
Question: can we do it without use of loops?
Script is the sequence of the Python expressions written in the file. So far we typed them directly to the python prompt.
import numpy as np
Nmax = 1000
M = np.zeros(Nmax) # we need to preallocate space
x=0.5
allN = range(1, Nmax+1)
for N in allN:
M[N-1] = np.pow(1+x/N, N) # position in array starts from 0!
import matplotlib.pyplot as plt
plt.plot(allN, M, '.-')
plt.grid(True)
plt.xlabel("N, number of payments per year")
plt.ylabel("$M_N$, return on investment") # Note it understands LaTeX!
plt.title("Return on investment vs number of payments")
plt.savefig("return_on_investment.png")Let’s save it to the file plot_return_on_investment.py.
Now we can edit the file and assign any x and
Nmax.
To execute the script directly in the shell
There is no visible output, but the figure regenerated.
Now we are free to massage our script to satisfy our needs.
Unlike functions scripts modify Workspace variables
import numpy as np
Nmax = 1000
M = np.zeros(Nmax) # we need to preallocate space
x=0.5
allN = range(1, Nmax+1)
for N in allN:
M[N-1] = np.pow(1+x/N, N) # position in array starts from 0!
import matplotlib.pyplot as plt
plt.plot(allN, M, '.-')
plt.grid(True)
plt.xlabel("N, number of payments per year")
plt.ylabel("$M_N$, return on investment") # Note it understands LaTeX!
plt.title("Return on investment vs number of payments")
plt.savefig("return_on_investment.png")Used for separation of a meaningful chunk of code
def function_name(arg1, arg2, arg3, ..., argN, karg1=val1, karg2=val2, ..., kargN=valN)
"""Optional but super handy doc string"""
# body of the function
# notice the indentation!
.
.
return (ret1, ret2, ret3, ... , retN)args, kargs, and rets are
optional and defined as needed.print function is a good
exampleIn [5]: def minmax(n1, n2=0):
...: """Take two numbers and return them in ascending order.
...: The second argument is optional, if not provided 0 will be used.
...: """
...: if n1 < n2:
...: return (n1, n2) # this is actually one value, i.e. *tuple* of 2 numbers
...: else:
...: return (n2, n1)
...: # note that python will never reach this point
...:
In [6]: minmax(23)
Out[6]: (0, 23)
In [7]: minmax(4, -2)
Out[7]: (-2, 4)
In [8]: minmax(1, 5)
Out[8]: (1, 5)We can also ask documentation about our function
In [15]: minmax?
Signature: minmax(n1, n2=0)
Docstring:
Take two numbers and return them in ascending order.
The second argument is optional, if not provided 0 will be used.
File: ~/jobs/wm/2026.fall_practical_computing_for_scientists_256/lecture03/plots_python/<ipython-input-14-a8b09f68fc26>
Type: functionUnlike scripts, functions leave Workspace intact.
There are exceptions, in particular in numpy world!
What we will get back?
Canonical example: factorial We can rewrite it as Notice that
In [10]: def fact(n):
...: if n <= 1:
...: return 1
...: return n * fact(n-1)
...:
In [11]: fact(3)
Out[11]: 6
In [12]: fact(5)
Out[12]: 120While certain code will look more elegant with recursion, there is a hard limit for number of the recursive calls.
Also generally such code is slower than if you can implement it with loops.
You might ask how computer calculates ?
One way is to do it by approximating value of via Taylor expansion
import math
import numpy as np
def mysin(x, N=10):
s=0
for n in range(0,N+1):
s = s + np.pow(-1.0, n) * np.pow(x, 2*n+1) / math.factorial( 2*n +1)
# we could have use our own factorial implementation as well
# notice that direct use of factorial is *bad* idea
# since as n grows, it has to recaluclate same things (n-1)! again and again
# it would be better to rethink it
# There is incoming problem for large n! factorial overflow the float representation
return s>>> mysin(math.pi)
np.float64(1.0348185903053497e-11)
>>> mysin(math.pi, N=50)
np.float64(3.3280566969799443e-16)
>>> mysin(math.pi/2)
np.float64(1.0000000000000002)
>>> mysin(math.pi/2, N=50)
np.float64(1.0000000000000002)Spoiler, this is not how trig functions are calculated for arbitrary . Usually, via trig identities brought to the smallest usable value and then it is calculated. Recall that expansion requires the least members of the sum the close to 0 (since our equation was expansion of around 0.
mysin implementation to the
numpy.sin oneimport numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2*np.pi, 100) # we create 100 equidistant points
y_numpy_sin = np.sin(x) # calculate sin for all points of array in one go
# unfortunately mysin cannot work with array so we have to loop over x values
y_mysin = x*0 # preallocating array
for idx, xp in enumerate(x):
y_mysin[idx] = mysin(xp)
plt.figure(1)
plt.clf()
plt.plot(x, y_numpy_sin, label='numpy sin')
plt.plot(x, y_mysin, label='my sin')
plt.legend()
plt.grid(True)
plt.xlabel("Angle (rad)")
plt.ylabel("$\sin$ value")
plt.title("Comparison of numpy and our own $\sin$ calculations")
plt.figure(2)
plt.clf()
plt.plot(x, y_numpy_sin-y_mysin, label='difference')
plt.grid(True)
plt.legend()
plt.xlabel("Angle (rad)")
plt.ylabel("np.sin(x) - mysin(x)")
plt.title("Comparison of numpy and our own $\sin$ calculations")By now we completed equivalent of CSCI 141 class :) The rest is mastering what we know.
The major omitted pieces
We will talk about them as needed or avoid them completely. After all numerical computations usually do not require fancy things.
The sliver of python iceberg can be seen in python tutorial.