$ mkdir ~/cs170/labs/lab16 $ cd ~/cs170/labs/lab16
A recursive function is a function that makes a call to itself. Half of you have seen it before, as a mechanism to repeat code. However, that is not really the true power of a recursive function. We can use recursive functions to break a problem down into simpler components, and use those components to build the full solution.
Any code that can be written using recursion can be written using loops. However, sometimes it is easier to program an algorithm using recursion. One case when it is easier to program an algorithm recursively is when it is defined recursively. For example, the Fibonacci sequence is a well-known mathematical sequence in which each term is the sum of the two previous terms. Because the Fibonacci sequence is defined recursively, it is natural to write a recursive function to determine the nth number in the sequence.
Create a file fibonacci.py, and write a
function fibonacci(n)
in this file. This function
should recursively compute the nth fibonacci number.
If fib(n) is the nth term of the sequence, then the sequence can be
defined as follows:
fib(0) = 0
fib(1) = 1
fib(n) = fib(n-1) + fib(n-2) (for all n>1)
>>> fibonacci(0) 0 >>> fibonacci(1) 1 >>> fibonacci(2) 1 >>> fibonacci(3) 2 >>> fibonacci(4) 3 >>> fibonacci(5) 5
One of the oldest algorithms known is the Euclidean algorithm for computing the greatest common denominator of two numbers. GCD is used when simplifying fractions, and sounds like it should be pretty complicated. However, it is one of the most beautiful algorithms in existence.
Create a file called euclidean.py, and create a function
gcd(a, b)
which computes the greatest common common
denominator of the integers a and b. The logical mechanism for this
function would be to check every integer in the range [1, min(a,
b)]. However, there is an elegant recursive definition that can
compute the gcd:
gcd(a, 0) = a
gcd(a, b) = gcd(b, a mod b)
>>> gcd(3, 6) 3 >>> gcd(6, 3) 3 >>> gcd(1, 9001) 1 >>> gcd(36, 84) 12
Your base case is that the integer b is 0. In this case, you want to return the value a.
Your recursive case is simply the recursive call with the
value of b for parameter a, and the value a % b
for the parameter b. Don't forget to return this value!
Remember the Fraction
class you wrote about three
weeks ago? Well, there are some operations that might produce a
non-simplified fraction. If you were to show this to a
mathematician, you would likely give them an aneurism. Add the
Euclidean GCD function to your fraction.py file, and
use the computed GCD to simplify your fractions.
One nice thing about recursive functions is that they can sometimes be more efficient. Last semester, we made you write the power function using a loop. However, this function is a O(n) function. Using recursion, we can improve things pretty well.
In a file called power.py, create a function
called power(x, y)
. This function should follow the
following recursive definition for power, which should
perform fewer multiplications:
x1 = x
xy = xy/2*xy/2
(if y is even and greater than 1)
xy = x*x(y-1)/2*x(y-1)/2
(if y is odd and greater than 2)
You should also write a function called loop_pow(x, y)
,
which computes the power using the traditional loop
methodology. For both of these functions, you should return both
the value of the power, and the number of multiplications required
to compute the value. Test both functions, and make sure the
recursive definition performs fewer multiplications.
>>> power(2, 3) (8, ###) >>> loop_power(2, 3) (8, 2) >>> loop_power(2, 10) (1024, 9) >>> power(2, 10) (1024, ###) >>> power(9, 15) (205891132094649, ###) >>> loop_power(9, 15) (205891132094649, 14)
Example censored to not spoil the surprise!
Notice in the above recursive definition that while there are really two recursive calls to power, you only really need to perform one in each recursive case. You can store that value in a variable, and use that variable in your multiplications.
How does this recursive definition compare in run times? Let's
use a timer and plot the results! Try computing the powers of 2
from 1 to 500, and plot the results as you did in the last lab.
If you are mind is not too melted after todays recursion lab, you
can compare the performance of the **
operator to the
above functions.
When you have finished, create a tar file of your lab16
directory. To create a tar file, execute the following commands:
cd ~/cs170/labs tar czvf lab16.tgz lab16/
To submit your activity, go to cseval.roanoke.edu. You should
see an available assignment called Lab Assignment 16
.
Make sure you include a header listing the authors of the file.