The recursive definitions mentioned above all involved trivial
linear recursive processes. The next example illustrates the kind of analysis
a student might perform on a less trivial problem. Consider the standard
recursive definition of the fibonacci function.
fibonacci =: monad define script if. y. < 2 do. y. else. (fibonacci y. - 1) + fibonacci y. - 2 end. )
Program fibonacci (J Version)
Applying
fibonacci to the argument 5 produces a result of 5. Tracing
fibonacci produces the output
traced_fibonacci 5 Entering, input = 5 Entering, input = 4 Entering, input = 3 Entering, input = 2 Entering, input = 1 Leaving, result = 1 Entering, input = 0 Leaving, result = 0 Leaving, result = 1 Entering, input = 1 Leaving, result = 1 Leaving, result = 2 Entering, input = 2 Entering, input = 1 Leaving, result = 1 Entering, input = 0 Leaving, result = 0 Leaving, result = 1 Leaving, result = 3 Entering, input = 3 Entering, input = 2 Entering, input = 1 Leaving, result = 1 Entering, input = 0 Leaving, result = 0 Leaving, result = 1 Entering, input = 1 Leaving, result = 1 Leaving, result = 2 Leaving, result = 5 5
Analyzing the
fibonacci definition, we notice that there are two
recursive calls to fibonacci inside this definition. We next write
the continuations of each of these calls.
monad define 'y. + fibonacci n - 2' monad define '(fibonacci n - 1) + y.'
fibonacci is not tail recursive. In fact, each continuation contains a
recursive call to fibonacci. We also notice, from the traced output, that
fibonacci makes applications of fibonacci to the same argument.
Consider the problem of evaluating fibonacci 3. Two continuations must be
formed.
c1 =: monad define'y. + fibonacci 0' c2 =: monad define'y. + fibonacci 1'
The value of
fibonacci 3 is represented by the expression
c2 c1 1. Next, consider the problem of evaluating fibonacci 4.
Three continuations must be formed.
c1 =: monad define'y. + fibonacci 0' c2 =: monad define'y. + fibonacci 1' c3 =: monad define'y. + fibonacci 2'
The value of
fibonacci 4 is represented by the expression
c3 c2 c1 1.
Next we consider the number of times fibonacci is called while evaluating
fibonacci. Define fib_work to be the number of times fibonacci
is called while evaluating fibonacci. We see that:
fib_work 0 = 1
fib_work 1 = 1
fib_work 2 = 3
fib_work 3 = 5
fib_work 4 = 9
fib_work 5 = 15
It is easy to establish the recurrence formula for fib_work
fib_work n = 1 + (fib_work n - 1) + fib_work n - 2
Assuming that the execution time of
fibonacci is proportional to
fib_work, then the order of fibonacci is
fib_work which is, itself, a fibonacci function. This
analysis leads to a laboratory experiment [How 94] in which students conduct
timing measurements of the number of recursive calls per second a
workstation can make to fibonacci. Since fibonacci would make
1146295688027634168201 recursive calls while evaluating fibonacci 100, a
workstation which can perform 1,000,000 recursive calls per second would require approximately
1146295688027634 seconds (more than 363487 centuries!) to evaluate fibonacci 100.
This laboratory provides the opportunity for students to deal with formal analysis,
experimental measurements, recursion and iteration.