.
So the sequence of numbers goes like this:
n F(n) 1 1 2 1 3 2 4 3 5 5 6 8 7 13 8 21 9 34 10 55and so on. The Fibonacci functions comes up a lot in computer science and also in nature. It turns out that when you divide the nth Fibonacci number by the (n-1)th, you get an approximation to the Golden Ratio, or about 1.618033988, one of those important numbers like Pi and e. The higher the value of n, the better the approximation. Fibonacci numbers also have interesting number theoretical properties. Let's look at a function that computes the nth Fibonacci number:
int F (int n) {
int F_i, /* the "current" fibonacci number */
F_i_minus_1, /* the "previous" one */
tmp; /* temporary */
int i;
/* we start with i=2, so F(i-1) is 1, F(i) is 1 */
F_i_minus_1 = 1;
F_i = 1;
/* we know F(1) and F(2), let's get F(3)..F(n) */
for (i=3; i<=n; i++) {
/* tmp is F(i) */
tmp = F_i_minus_1 + F_i;
/* F(i-1) is previous value */
F_i_minus_1 = F_i;
/* F(i) is current value */
F_i = tmp;
}
/* all done... */
return F_i;
}
So to get a table of Fibonacci numbers, we can have a simple main
like this:
#include <stdio.h>
int main () {
int i;
for (i=1; i<=46; i++) printf ("%d %d\n", i, F(i));
return 0;
}
(Why 46? F(47) overflows a 32-bit integer; these numbers get big fast.)
.
Note that this definition is in terms of itself; it is recursive. We've
already seen an iterative definition of factorial in C:
int factorial (int n) {
int i, product;
product = 1;
for (i=1; i<=n; i++) product = product * i;
return product;
}
But we can just directly code the function from the definition
instead of doing the algorithm:
int factorial (int n) {
if (n == 0)
return 1;
else
return n * factorial (n - 1);
}
So factorial is calling upon itself to figure out values
of the factorial function for different values of n. You can
think of each invokation of factorial as a separate "copy,"
with its own n parameter.
#include <stdio.h>
void print_between (int first, int last) {
int i;
for (i=first; i<=last; i++) printf ("%d\n", i);
}
int main () {
int n, m;
printf ("Enter two numbers: ");
scanf ("%d %d", &n, &m);
print_between (n, m);
return 0;
}
So far so good, it's pretty clear what's going on here. Now let's
rewrite the print_between function, this time using recursion:
void print_between (int first, int last) {
if (first <= last) { /* base case */
printf ("%d\n", first);
print_between (first+1, last);
}
}
When we call this function with, say print_between (2, 6),
the following sequence occurs:
Function Call Output
print_between (2, 6);
printf ("%d", 2); 2
print_between (3, 6);
printf ("%d", 3); 3
print_between (4, 6);
printf ("%d", 4); 4
print_between (5, 6);
printf ("%d", 5); 5
print_between (6, 6);
printf ("%d", 6); 6
return
return
return
return
return
(The returns are where each function call ends.)
What good is this? Not
much, it's just a contrived example of recursion. But what happens
if we switch the order of the printf and recursive function call:
void print_between (int first, int last) {
if (first <= last) { /* base case */
print_between (first+1, last);
printf ("%d\n", first);
}
}
That simple change causes the function to print the sequence backwards:
Function Call Output
print_between (2, 6);
print_between (3, 6);
print_between (4, 6);
print_between (5, 6);
print_between (6, 6);
printf ("%d", 6); 6
return
printf ("%d", 5); 5
return
printf ("%d", 4); 4
return
printf ("%d", 3); 3
return
printf ("%d", 2); 2
return
Each recursive function call "remembers" it's own value for last,
and prints it out after recursively calling print_between.
What good is this? Okay, it's still not much good; we could still do it
with stuff we already know like a for loop.
#include <stdio.h>
void print_backwards (void) {
float f;
/* read in a number */
scanf ("%f", &f);
/* if not the end of input... */
if (f != -1.0) { /* f == -1 is the base case */
/* recursively get more numbers */
print_backwards ();
/* print the current number */
printf ("%f\n", f);
}
}
int main () {
printf ("Enter some numbers, followed by -1: ");
print_backwards ();
}
Let's take another look at the Fibonacci function, this time recursively:
int F (int n) {
if (n == 1 || n == 2) return 1; /* base case */
return F(n-1) + F(n-2);
}
The old version was about fourteen lines of C code. This is four lines, with
no variables. More efficient, right? Wrong; this function takes a lot
more time because it needlessly recomputes many factorial values.
Although we can try to make this one faster using arrays (from the next
chapter), in general recursive functions are a little more time
consuming than their iterative cousins. Doing a function call in machine
language takes a fair amount of time compared to doing one iteration
of a loop, so sometimes recursion is less efficient. Sometimes, though,
it is the most natural way of looking at a problem and makes the
code more readable.
Please begin reading Chapter 5 in your book.