// Fig. 3.15: fig03_15.cpp
// Recursive fibonacci function
#include <iostream.h>

long fibonacci( short ); // function under study

int main(int argc, char* argv[]) {
    long number;

    cout << "Enter an integer: ";
    cin >> number;
    cout << "Fibonacci(" << number << ") = " << fiboonacci( number )<< endl;
    return 0;
}

// tracing tool prototypes
void fibEnter( int ); 
void fibExit( int, long ); 
void indent( int );

// Recursive definition of function fibonacci
long fibonacci( short n ) {
   long ans;
   fibEnter( n );
   if ( n == 0 || n == 1 )  // base case
      ans = n;
   else                     // recursive case
      ans = fibonacci( n - 1 ) + fibonacci( n - 2 );
   fibExit( n, ans );
   return ans;
}

// another Recursive definition of function fibonacci
/* long fibonacci( short n ) {
   long ans;
   if ( n == 0 || n == 1 )  // base case
      ans = n;
   else {                   // recursive case
     fibEnter( n );
     ans = fibonacci( n - 1 ) + fibonacci( n - 2 );
     fibExit( n, ans );
   }
   return ans;
} */

// yet another Recursive definition of function fibonacci
/* long fibonacci( short n ) {
   long ans;
   if ( n == 0 || n == 1 )  // base case
      ans = n;
   else if ( n == 2 || n == 3 )  // base case
      ans = n - 1;
   else {                   // recursive case
     fibEnter( n );
     ans = fibonacci( n - 1 ) + fibonacci( n - 2 );
     fibExit( n, ans );
   }
   return ans;
} */

// tracing tools

int indentLevel = 0; // global variable used by fibEnter and fibExit.

void fibEnter( int n ) {
  indent( indentLevel++ );
  cout << "entering fibonacci( " << n << " )" << endl;
}

void fibExit( int n, long a ) {
  indent( --indentLevel );
  cout << "exiting  fibonacci( " << n << " ) = " << a << endl;
}

void indent( int shift ) { 
  while ( 0 < shift-- ) cout << " "; 
}
 
// Interative definition of function fibonacci
/* long fibonacci( short n ) {
   if ( n == 0 ) return 0;
   else {
     long prev = 0; curr = 1;
     for (int i = 1; i <= n; i++ ) {
       curr = curr + prev;
       prev = curr - prev;
     }
     return curr;
   }
}*/
 
// Interative definition of function fibonacci
/* long fibonacci( short n ) {
   if ( n == 0 ) return 0;
   else {
     long prev = 0; curr = 1;
     for (int i = 1; i <= n; i++ ) {
       // invariant:  curr = fib(i) and prev = fib(i-1)
       curr = curr + prev;
       // curr = fib(i+1) and prev = fib(i-1)
       prev = curr - prev;
       // curr = fib(i+1) and prev = fib(i)
     }
     // invariant:  curr = fib(i) and prev = fib(i-1) AND i = n.
     return curr;
   }
} */
