Tutorial A8 – Solutions¶
1 Write a functions that takes two numbers as input and returns the sum.
[1]:
def calc_sum(a, b):
"""Calculate the sum of two values"""
return a + b
print(calc_sum(1, 2))
3
2 Write a function that computes the cumulative sum of values in a sequence and returns the result as a list. Demonstrate that it works. Hint: You can use a list to pass a sequence to a function.
[2]:
def cumsum(seq):
"""Compute cumulative sum
Args:
seq: Sequence of numbers
Returns:
Cumulative sum as list
"""
result = []
for i, _ in enumerate(seq, 1):
result.append(
sum(seq[:i])
)
return result
print(cumsum(range(10)))
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
3 Write a function factorial(n)
that returns the factorial of an integer \(n\). What happens if you pass a float?
[3]:
def factorial(n):
"""Compute the factorial of an integer"""
product = 1
while n > 1:
product *= n
n -= 1
return product
[4]:
# Function returns the correct answer
for i in range(5):
print(factorial(i))
1
1
2
6
24
[5]:
# Function returns nonsense if you pass a float
print(factorial(2.4))
3.36
[6]:
# How to ensure n is an integer?
def factorial_save(n):
"""Compute the factorial of an integer"""
assert isinstance(n, int)
# Raise an error if n is not an int
product = 1
while n > 1:
product *= n
n -= 1
return product
[7]:
# Function raises an error if n is not an int
print(factorial_save(2.4))
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-7-c24e4c730d4c> in <module>
1 # Function raises an error if n is not an int
----> 2 print(factorial_save(2.4))
<ipython-input-6-64b99c35c800> in factorial_save(n)
3 """Compute the factorial of an integer"""
4
----> 5 assert isinstance(n, int)
6 # Raise an error if n is not an int
7
AssertionError:
Advanced 1 Write a function exp(x)
that takes a float x
as an argument and returns \(\mathrm{e}^x\) approximated as the Taylor series up to order \(n\) around the expansion point \(a = 0\). Make the order \(n\) an optional argument that defaults to \(n = 5\). You can call factorial(n)
from within exp(x)
to calculate the factorials.
For \(f(x) = \mathrm{e}^x\), \(a = 0\):
[8]:
def exp(x, n=5):
"""Calculate e**x approximated by a Taylor expansion around 0
Args:
x (float): Input value
n (int): Expansion order
Returns:
Result (float)
"""
assert isinstance(n, int)
result = 1 # Zero order approximation
for i in range(1, n+1):
# Add term
result += x ** i / factorial(i)
return result
[9]:
# Generate 21 values in the open interval (-1, 1)
x = [x*0.1 for x in range(-10, 11)]
# Call our function (default n = 5)
for x_ in x:
print(exp(x_))
0.3666666666666667
0.40591675000000005
0.44900266666666666
0.49643691666666656
0.5487519999999999
0.6065104166666666
0.6703146666666665
0.74081725
0.8187306666666667
0.9048374166666667
1.0
1.1051709166666666
1.2214026666666666
1.34985775
1.4918186666666666
1.6486979166666667
1.8220480000000003
2.013571416666667
2.225130666666667
2.45875825
2.7166666666666663
[10]:
# Call our function (lower order)
for x_ in x:
print(exp(x_, n=2))
0.5
0.505
0.52
0.5449999999999999
0.58
0.625
0.6799999999999999
0.745
0.8200000000000001
0.905
1.0
1.105
1.22
1.345
1.48
1.625
1.7800000000000002
1.9450000000000003
2.12
2.3049999999999997
2.5
Advanced 2 What is wrong with these two functions:
[11]:
def broken():
print(x)
x = "NEW"
return(x)
x = "STRING"
[12]:
def broken_counter():
counter += 1
counter = 1
Advanced 3 (Warning: the solution to this problem touches a concept we have not discussed in the lesson. This is a really advanced exercise.) Ever solved a “Jumble”-puzzle? Write a function that expects a string and returns every possible re-combination of the letters to help you find the terms hidden behind “rta”, “atob” and “rbani”. You can test your function with the built-in function itertools.permutations
from the itertools
module. How many possible combinations does this
return? Does the solver help you with this one: “ibaptlienxraoc”? Hint: Functions can call themselves. Try to pick letters from the string one by one to find a possible re-combination.
[13]:
# Solution using recursion
def recombine(pool, combination=''):
if len(pool) == 0:
# Pool exhausted, combination found
combinations.append(combination)
else:
for i in range(len(pool)):
# Take out one element and append it to combination
recombine(pool[0:i] + pool[i + 1:], combination + pool[i])
[14]:
combinations = []
recombine("rta")
print(*combinations, sep=" ")
rta rat tra tar art atr
[15]:
combinations = []
recombine("atob")
print(*combinations, sep=" ")
atob atbo aotb aobt abto abot taob tabo toab toba tbao tboa oatb oabt otab otba obat obta bato baot btao btoa boat bota
[16]:
combinations = []
recombine("rbani")
print(*combinations, sep=" ")
rbani rbain rbnai rbnia rbian rbina rabni rabin ranbi ranib raibn rainb rnbai rnbia rnabi rnaib rniba rniab riban ribna riabn rianb rinba rinab brani brain brnai brnia brian brina barni barin banri banir bairn bainr bnrai bnria bnari bnair bnira bniar biran birna biarn bianr binra binar arbni arbin arnbi arnib aribn arinb abrni abrin abnri abnir abirn abinr anrbi anrib anbri anbir anirb anibr airbn airnb aibrn aibnr ainrb ainbr nrbai nrbia nrabi nraib nriba nriab nbrai nbria nbari nbair nbira nbiar narbi narib nabri nabir nairb naibr nirba nirab nibra nibar niarb niabr irban irbna irabn iranb irnba irnab ibran ibrna ibarn ibanr ibnra ibnar iarbn iarnb iabrn iabnr ianrb ianbr inrba inrab inbra inbar inarb inabr
[17]:
# Test with built-in function
import itertools
print(*["".join(x) for x in itertools.permutations("rta")], sep=" ")
rta rat tra tar art atr
[18]:
# The number of possible recombinations growths fast (n!)
import math
math.factorial(len("ibaptlienxraoc"))
[18]:
87178291200