You are on page 1of 5

Part Three Fibonacci Series.

nb

Part Three
The Fibonacci Series
"Nectar of the gods"

J. Hamilton
It is well known in civilized circles that no discussion of computational methods is complete without at least one reference to
the Fibonacci Series.

Recursion without branching


This function begins summing as it makes the recursive call. Notice that each call generates only one additional call (no
branching).

No safety net
When you give Mathematica multiple patterns, it will try to match the most specific pattern first
Clear@fibD;
fib@a_, b_, n_IntegerD := fib@b, a + b, n - 1D;
fib@a_, b_, 0D := a;
fib@a_, b_, 1D := b;
fib::usage = "Arguments are a, b, n where a
and b are the initial numbers and n is the number of steps.";

This looks pretty good unless you have a clueless user. Let's try:
fib@a_, b_, -5D := "Enough already";
fib@1, 1, -1D
Enough already

Safer
We limit the actions of the clueless (such as myself before AM coffee) by using an explicit condition in the function
definition.
Clear@fibD;
fib@a_, b_, n_Integer ; n > 1D := fib@b, a + b, n - 1D;
fib@a_, b_, 0D := a;
fib@a_, b_, 1D := b;

Let's try this again:

Part Three Fibonacci Series.nb

fib@a_, b_, -5D := "Enough already";


fib@1, 1, -1D
fib@1, 1, -1D

Now the function is left unresolved because none of the patterns match the input. If you wanted to you could also add one
more pattern to catch "none of the above". The triple underscore matches a sequence of zero, one, or more entries of anything. This would insure that the function is always resolved.
fib@___D := "This is the most general pattern.";
fib@1, 1, -1D
This is the most general pattern.
fib@D
This is the most general pattern.
fib@a, b, , d, 8a, b, c<D
This is the most general pattern.

Execution time
Here is the computational time and the result of the functional evaluation.
Timing@fib@1, 1, 30DD
80. Second, 1346269<

Here is what Mathematica knows about the function. One ? gives the usage information and two ?? dumps everything.
? fib
Arguments are a, b, n where a and b are the initial numbers and n is the number of steps.

?? fib
Arguments are a, b, n where a and b are the initial numbers and n is the number of steps.
fib@a_, b_, n_Integer ; n > 1D := fib@b, a + b, n - 1D
fib@a_, b_, 0D := a
fib@a_, b_, 1D := b
fib@a_, b_, -5D := Enough already
fib@___D := This is the most general pattern.

Part Three Fibonacci Series.nb

Recursion with branching


Each of the following versions of the Fibonacci function makes two recursive calls. The slow version saves none of the
intermeduate values, while the fast version saves every (new) intermediate value. The difference in computational time is
dramatic as n increases.

Computing (and recomputing) every node


Notice that the values for n=0 and 1 are defined using = (immediate assignment) rather then := (delayed assignment) in the
fib fuction above.
Clear@slowfibD;
slowfib@n_Integer ; n > 1D := slowfib@n - 1D + slowfib@n - 2D;
slowfib@0D = 1;
slowfib@1D = 1;
slowfib::usage = "Don't use this function";

Here is the computational time and the result of the functional evaluation. Because no intermediate values are stored, the
every path in the tree must be traversed. On this machine the time for n=25 was about 1 second, ... then 4 seconds at n=28, ...
now this.
Timing@slowfib@30DD

811.216 Second, 1346269<

Here is what Mathematica knows about the function. I specified all of this in the original definition.
? slowfib
Don't use this function

?? slowfib
Don't use this function
slowfib@0D = 1
slowfib@1D = 1

slowfib@n_Integer ; n > 1D := slowfib@n - 1D + slowfib@n - 2D

Computing once and storing


Clear@fastfibD;
fastfib@n_Integer ; n > 1D := fastfib@nD = fastfib@n - 1D + fastfib@n - 2D;
fastfib@0D = 1;
fastfib@1D = 1;
fastfib::usage = "This function is fast but uses memory";

Part Three Fibonacci Series.nb

Here is the computational time and the result of the functional evaluation. Because intermediate values are stored, only the
first path must be traversed. I run into the default limit on the number of recursive steps before I use a measurable amount of
time computing the answer.
Timing@fastfib@30DD

80. Second, 1346269<

Here is what Mathematica knows about the function. Notice that it contains much more than what I specified in the definition. This is also why I start every definition with the Clear[ ... ] statement. Presumably, if we now evaluate fastfib[31], it
sums fastfib[30] + fastfib[29] and is done. The fib function above has to start back at zero and recompute the full series.
? fastfib
This function is fast but uses memory

?? fastfib
This function is fast but uses memory
fastfib@0D = 1
fastfib@1D = 1
fastfib@2D = 2
fastfib@3D = 3
fastfib@4D = 5
fastfib@5D = 8
fastfib@6D = 13
fastfib@7D = 21
fastfib@8D = 34
fastfib@9D = 55
fastfib@10D = 89
fastfib@11D = 144
fastfib@12D = 233
fastfib@13D = 377
fastfib@14D = 610
fastfib@15D = 987
fastfib@16D = 1597
fastfib@17D = 2584
fastfib@18D = 4181
fastfib@19D = 6765

Part Three Fibonacci Series.nb

fastfib@20D = 10946
fastfib@21D = 17711
fastfib@22D = 28657
fastfib@23D = 46368
fastfib@24D = 75025
fastfib@25D = 121393
fastfib@26D = 196418
fastfib@27D = 317811
fastfib@28D = 514229
fastfib@29D = 832040
fastfib@30D = 1346269

fastfib@n_Integer ; n > 1D := fastfib@nD = fastfib@n - 1D + fastfib@n - 2D

You might also like