import SimpleOutput; /** * A number of implementations of functions to compute the nth * Fibonacci number. Intended as part of an answer key for * HW6 of CS152 99S. * * This can be used as a utility class (in which case it is recommended * that you use fibdp), or it can serve as a tester for the various * Fibonacci methods. In the latter case, the command line syntax is: * % java Fiboncci i1 i2 ... in * (which computes the i1th, i2th, ... inth Fibonacci number using * each technique, and reports on the time). * * @author Samuel A. Rebelsky * @version 1.0 of March 1999 */ public class Fibonacci { // +--------+-------------------------------------------------- // | Fields | // +--------+ /** * An array of computed Fibonacci numbers. Used for the * dynamic programming version of the function. Eventually, * FIB[n] is the nth Fibonacci number. When initialized, * FIB[n] is 0. */ protected long FIB[]; // +---------+------------------------------------------------- // | Methods | // +---------+ /** * Compute the nth Fibonacci number using the naive recursive * technique. * Pre: n >= 0 * Pre: the nth Fibonacci number >= Long.MAX_VALUE * Post: returns the nth Fibonacci number */ public long fib(long n) { // Base case: the 0th Fibonacci number is 0, the 1st // Fibonacci number is 1. if (n <= 1) return n; // Recursive case: the nth Fibonacci number is // the n-1st Fibonacci number + the n-2nd Fibonacci number. return fib(n-1) + fib(n-2); } // fib(long) /** * Compute the nth Fibonacci number using the naive recursive * technique, supplemented by dynamic programming. * Pre: n >= 0 * Pre: the nth Fibonacci number >= Long.MAX_VALUE * Post: returns the nth Fibonacci number */ public long fibdp(long n) { // Base case: the 0th Fibonacci number is 0, the 1st // Fibonacci number is 1. if (n <= 1) return n; // Is there a table? If not, make one. Takes advantage // of the fact that Java uses 0 as the default value for // longs (so we'll assume that any 0 entry is not yet // filled in). if (FIB == null) FIB = new long[(int) n+1]; // Is the table big enough? Needs to be checked in case // there are independent calls. if (FIB.length <= n) { // Remember the old table. long[] tmp = FIB; // Build a new table. FIB = new long[(int) n+1]; // Copy over the elements. for (int i = 0; i < tmp.length; ++i) { FIB[i] = tmp[i]; } // for } // if the table isn't big enough // Does the table have the entry? A nonzero entry means // that we've already computed the nth Fibonacci number. if (FIB[(int) n] != 0) return FIB[(int) n]; // If we've gotten this far, we need to compute the nth // Fibonacci number. FIB[(int) n] = fibdp(n-1) + fibdp(n-2); // And now that we've computed it, we can return it. return FIB[(int) n]; } // fibdp(long) /** * Compute the nth Fibonacci number using an iterative * technique. We keep track of the ith and i-1st Fibonacci * numbers, use them to generate the i+1st Fibonacci number, * and then update i. * Pre: n >= 0 * Pre: the nth Fibonacci number >= Long.MAX_VALUE * Post: returns the nth Fibonacci number */ public long fibit(long n) { int i; // Counter variable int ithfib; // The ith Fibonacci number int prevfib; // The previous Fibonacci number int nextfib; // The next Fibonacci number // The technique doesn't work for n = 0, so use the // default answer for that particular case. if (n == 0) return 0; // Initialize everything. i = 1; ithfib = 1; prevfib = 0; // Keep going until we reach n. while (i < n) { nextfib = ithfib + prevfib; // Move on to the next i. i = i + 1; // The old ith Fibonacci number is now the previous // Fibonacci number. prevfib = ithfib; // The old next Fibonacci number is now the new ith // Fibonacci number. ithfib = nextfib; } // while // i is now n, so the ith Fibonacci number is the nth Fibonacci // number. return ithfib; } // fibit(long) /** * Compute the nth Fibonacci number using a recursive algorithm * similar to the one used in fibit. * Pre: n >= 0 * Pre: the nth Fibonacci number >= Long.MAX_VALUE * Post: returns the nth Fibonacci number */ public long fibrec(long n) { if (n == 0) return 0; else return fibrec(n, 1, 1, 0); } // fibrec /** * Compute the nth Fibonacci number given the ith and i-1st * Fibonacci numbers. * Pre: n >= 1 * Pre: the nth Fibonacci number >= Long.MAX_VALUE * Post: returns the nth Fibonacci number */ public long fibrec(long n, long i, long ithfib, long prevfib) { // Base case: i is n, so the ith Fibonacci number is the // nth Fibonacci number. if (i == n) return ithfib; // Recursive case else return fibrec(n, i+1, ithfib+prevfib, ithfib); } // fibrec(long,long,long,long) // +------+---------------------------------------------------- // | Main | // +------+ /** * Get some values of N and compute. */ public static void main(String[] args) { // Create an array of inputs. long[] vals = new long[args.length]; // Create an array of results. long[] results = new long[args.length]; // Two time values, used to determine how long the various // computations take. long start; long stop; // The wonderful thing that does all the computation. Fibonacci computer = new Fibonacci(); // And something for output. SimpleOutput out = new SimpleOutput(); // Fill in the values. Use 0 if the user gives a bad // value. This is intended for testing only, so the // user interface is primitive at best. for (int i = 0; i < args.length; ++i) { try { vals[i] = Long.parseLong(args[i]); } catch (Exception e) { } } // for // "Prime" the various methods (so that there's not overhead // in loading their code, optimizing their code, or whatever // else the interpeter decides to do). computer.fib(3); computer.fibdp(3); computer.fibit(3); computer.fibrec(3); // Determine how long the basic method takes. start = System.currentTimeMillis(); for (int i = 0; i < vals.length; ++i) { results[i] = computer.fib(vals[i]); } // for stop = System.currentTimeMillis(); // Report out.println("Naive recursive method: "); for (int i = 0; i < vals.length; ++i) { out.println(" fib(" + vals[i] + ") = " + results[i]); } // for out.println(" COMPUTATION TOOK " + (stop-start) + " MILLISECONDS"); // Determine how long the dynamic processing technique takes start = System.currentTimeMillis(); for (int i = 0; i < vals.length; ++i) { results[i] = computer.fibdp(vals[i]); } // for stop = System.currentTimeMillis(); // Report out.println("Dynamic programming method: "); for (int i = 0; i < vals.length; ++i) { out.println(" fibdp(" + vals[i] + ") = " + results[i]); } // for out.println(" COMPUTATION TOOK " + (stop-start) + " MILLISECONDS"); // Determine how long the iterative technique takes start = System.currentTimeMillis(); for (int i = 0; i < vals.length; ++i) { results[i] = computer.fibit(vals[i]); } // for stop = System.currentTimeMillis(); // Report out.println("Iterative method: "); for (int i = 0; i < vals.length; ++i) { out.println(" fibit(" + vals[i] + ") = " + results[i]); } // for out.println(" COMPUTATION TOOK " + (stop-start) + " MILLISECONDS"); // Determine how long the other recursive technique takes start = System.currentTimeMillis(); for (int i = 0; i < vals.length; ++i) { results[i] = computer.fibrec(vals[i]); } // for stop = System.currentTimeMillis(); // Report out.println("Other recursive method: "); for (int i = 0; i < vals.length; ++i) { out.println(" fibrec(" + vals[i] + ") = " + results[i]); } // for out.println(" COMPUTATION TOOK " + (stop-start) + " MILLISECONDS"); } } // class Fibonacci