In [1]:
import pytest
The Fibonacci series is valid only for $n \ge 0$. Add to the Fibonacci function in this notebook a check that raises an exception if $n < 0$. Try some invalid data cases to check that an exception is raised.
Optional: Use pytest to test that an exception is raised for some $n < 0$ cases.
In [4]:
def f(n):
"Compute the nth Fibonacci number using recursion"
if n < 0:
# Raise error if n is less than 0
raise ValueError('Fibonacci number can be calculated only for n greater than or equal to 0')
if n == 0:
return 0 # This doesn't call f, so it breaks out of the recursion loop
elif n == 1:
return 1 # This doesn't call f, so it breaks out of the recursion loop
else:
return f(n - 1) + f(n - 2) # This calls f for n-1 and n-2 (recursion), and returns the sum
# Test cases
print(f(4))
print(f(-1))
Test exceptions with pytest:
In [5]:
def f(n):
"Compute the nth Fibonacci number using recursion"
if n < 0:
# Raise error if n is less than 0
raise ValueError('Fibonacci number can be calculated only for n greater than or equal to 0')
if n == 0:
return 0 # This doesn't call f, so it breaks out of the recursion loop
elif n == 1:
return 1 # This doesn't call f, so it breaks out of the recursion loop
else:
return f(n - 1) + f(n - 2) # This calls f for n-1 and n-2 (recursion), and returns the sum
# Check that n < 0 raises a ValueError
with pytest.raises(ValueError):
f(-1)
with pytest.raises(ValueError):
f(-12)
with pytest.raises(ValueError):
f(-20)
In [6]:
def calculate_interest():
# Initial values
official_rate = 0.0025
rate_over = 0.0149
try:
# Get input from user
loan_principal = float(input('What is your loan principal? '))
#If loan principal is less than or equal to 0 raise an error
if loan_principal <= 0:
raise ValueError('Loan principal must be greater than 0')
days_period = float(input('What is the period (in days) of your loan? '))
#If the number of days is less than or equal to 0 raise an error
if days_period <= 0:
raise ValueError('Loan period must be greater than 0')
# Calculate interest
interest = (loan_principal
* ((official_rate + rate_over) / 365) # daily interest rate
* days_period)
return interest
except:
# Handle exceptions
print('Invalid value entered, try again')
return calculate_interest()
calculate_interest()
Out[6]:
Modify your program from the bisection exercise in Activity 04 to raise an error if the maximum number of iterations is exceeded. Reduce the maximum allowed iterations to test that an exception is raised.
Add any other checks on the input data that you think are appropriate.
In [7]:
def f(x):
#return x**3 - 6*x**2 + 4*x + 12
return x**2 + x - 20 # Roots = -5, 4
In [11]:
def compute_root(f, x0, x1, tol, max_it):
"""Computes the root of f between x0 and x1 using bisection,
stops if the value of f at the root is under tol or if max_it is reached
and returns the root, the value of f at the root and the number of iterations"""
# If tolerance is less than 0 return an error
if tol < 0:
raise ValueError('Tolerance must be greater than or equal to 0')
# If x0 or x1 is a root return it
if f(x0) == 0:
return x0, f(x0), 0
if f(x1) == 0:
return x1, f(x1), 0
# If f(x0)*f(x1) the function has no solution in the interval, so return an error
if f(x0)*f(x1) > 0:
raise RuntimeError('There is no solution between x0 and x1')
# Initialize iteration counter
i = 0
while True:
# Increment counter
i += 1
# If max_it is passed return an error
if i > max_it:
raise RuntimeError('Maximum number of iterations exceeded')
# Compute x_mid
x_mid = (x0 + x1) / 2
# Compute f for the three values
f_0, f_1, f_mid = f(x0), f(x1), f(x_mid)
# Check the value of f_0*f_mid to determine how to update the endpoints
if f_0*f_mid < 0:
x1 = x_mid
else:
x0 = x_mid
# Check if f is under tol
if abs(f_mid) < tol:
return x_mid, f_mid, i
# We don't need another return statement because if we pass max_it we return an error
# Test for the function f
x, f_x, num_it = compute_root(f, x0=3, x1=6, tol=1.0e-6, max_it=1000) # Ok
print('Approximate root:', x)
print('Value of f:', f_x)
print('Number of iterations:', num_it)
print('-----------------------------------------------------------')
x, f_x, num_it = compute_root(f, x0=3, x1=6, tol=1.0e-6, max_it=10) # Maximum iterations exceeded
x, f_x, num_it = compute_root(f, x0=3, x1=6, tol=-5, max_it=1000) # Tolerance less than zero
x, f_x, num_it = compute_root(f, x0=5, x1=6, tol=1.0e-6, max_it=1000) # No root in the interval