algorithms matter

This example of why the right algorithm matters comes directly from my textbook. Here's the C implementation:

Bad:

#include <stdio.h>
#include <stdlib.h>
long int fib(long int n) {
  if (n==0)
    return 1;
  if (n==1)
    return 1;
  return fib(n-1) + fib(n-2);
}
int main(int argc, char *argv[]) {
  if (argc <= 1) {
    fprintf(stderr, "argument?\n\n");
    exit(1);
  }
  long int n = atol(argv[1]);
  printf("f(%li) = %li\n",n,fib(n));
  return 0;
}

Good:

#include <stdio.h>
#include <stdlib.h>
long int fib(long int n) {
  long a=1, b=1, c;
  int i;
  for (i = 1;i < n; i++){
    c = a + b; a = b; b = c;
  }
  return b;
}
int main(int argc, char *argv[]) {
  if (argc <= 1) {
    fprintf(stderr, "argument?\n\n");
    exit(1);
  }
  long int n = atol(argv[1]);
  printf("f(%li) = %li\n",n,fib(n));
  return 0;
}

Output:

$ time ./fib2 38 ; time ./fib1 38
f(38) = 63245986

real	0m0.002s
user	0m0.000s
sys	0m0.004s
f(38) = 63245986

real	0m1.492s
user	0m1.428s
sys	0m0.004s

And you can show how nicely the good algorithm scales up by pulling out a bigint library, like Java's BigInteger:

public class fib3 {
  public static String fib(int n) {
    java.math.BigInteger a,b,c;
    int i;
    a = b = java.math.BigInteger.ONE;
    for (i = 1;i < n; i++) {
      c = a.add(b); a = b; b = c;
    }
    return b.toString();
  }
  public static void main(String[] args) {
    if (args.length < 1) {
      System.err.println("argument?");
      System.exit(1);
    }
    int n = Integer.parseInt(args[0]);
    System.out.print("f(" +
      Integer.toString(n) + ") = ");
    System.out.println(fib(n));
  }
}