<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv=Content-Type content="text/html; charset=iso-8859-1">
<META content="MSHTML 6.00.6000.16788" name=GENERATOR>
<STYLE></STYLE>
</HEAD>
<BODY>
<DIV><FONT face="Courier New" size=2>Fib cannot realy run in time O(n), because 
(+ n m) does not run in time O(1) for large values of n and m. With the function 
I posted yesterday (: very much like yours :) I find: </FONT><FONT 
face="Courier New" size=2><FONT face="Courier New" size=2>(#lang scheme no 
debugging) (all time in milliseconds)</FONT></DIV>
<DIV>&nbsp;</DIV></FONT>
<DIV><FONT face="Courier New" size=2>(void (time (fib 100))) cpu time: 0 real 
time: 0 gc time: 0<BR>(void (time (fib 1000))) cpu time: 0 real time: 0 gc time: 
0<BR>(void (time (fib 10000))) cpu time: 0 real time: 0 gc time: 0<BR>(void 
(time (fib 100000))) cpu time: 1360 real time: 1391 gc time: 265<BR>(void (time 
(fib 500000))) cpu time: 35641 real time: 36110 gc time: 7338</FONT></DIV>
<DIV><FONT face="Courier New" size=2></FONT>&nbsp;</DIV>
<DIV><FONT face="Courier New" size=2>The last call&nbsp;takes about&nbsp;26 
times the time&nbsp;of the last but one call. If fib would&nbsp;run in&nbsp;time 
O(n), you would expect a factor 5. </FONT></DIV>
<DIV><FONT face="Courier New" size=2></FONT>&nbsp;</DIV>
<DIV><FONT face="Courier New" size=2>Jos</DIV>
<DIV><BR></DIV></FONT>
<DIV><FONT face="Courier New" size=2>----- Original Message ----- </FONT>
<DIV><FONT face="Courier New" size=2>From: "Stephen Bloch" &lt;</FONT><A 
href="mailto:sbloch@adelphi.edu"><FONT face="Courier New" 
size=2>sbloch@adelphi.edu</FONT></A><FONT face="Courier New" 
size=2>&gt;</FONT></DIV>
<DIV><FONT face="Courier New" size=2>To: &lt;</FONT><A 
href="mailto:laalaalovesu@yahoo.com"><FONT face="Courier New" 
size=2>laalaalovesu@yahoo.com</FONT></A><FONT face="Courier New" 
size=2>&gt;</FONT></DIV>
<DIV><FONT face="Courier New" size=2>Cc: &lt;</FONT><A 
href="mailto:plt-scheme@list.cs.brown.edu"><FONT face="Courier New" 
size=2>plt-scheme@list.cs.brown.edu</FONT></A><FONT face="Courier New" 
size=2>&gt;</FONT></DIV>
<DIV><FONT face="Courier New" size=2>Sent: Thursday, January 08, 2009 3:50 
PM</FONT></DIV>
<DIV><FONT face="Courier New" size=2>Subject: Re:[plt-scheme] Dr.Scheme freezes 
on (fib 100) recursion</FONT></DIV></DIV>
<DIV><FONT face="Courier New"><BR><FONT size=2></FONT></FONT></DIV><FONT 
face="Courier New" size=2>&gt; <BR>&gt; On Jan 8, 2009, at 1:45 AM, laa laa 
wrote:<BR>&gt; <BR>&gt;&gt; my son and i coded a program to compute fibonacci 
sequences. it&nbsp; <BR>&gt;&gt; works fine for low numbers, but when you try to 
do something higher&nbsp; <BR>&gt;&gt; like (fib 100) Dr.Scheme freaks out and 
freezes up. we're wondering&nbsp; <BR>&gt;&gt; what's going on? is there a 
reason for this. . . .<BR>&gt;&gt;<BR>&gt;&gt; (define (fib 
n)<BR>&gt;&gt;&nbsp;&nbsp; (if (&lt; n 
3)<BR>&gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<BR>&gt;&gt;&nbsp;&nbsp; (+ 
(fib (- n 1)) (fib (- n 2)))))<BR>&gt; <BR>&gt; This is one of my favorite (for 
classroom use) examples of algorithm&nbsp; <BR>&gt; (in)efficiency.&nbsp; It is 
obviously a "correct" definition, but think&nbsp; <BR>&gt; about how long it 
takes.&nbsp; The only number it actually knows is 1, and&nbsp; <BR>&gt; the only 
operation it does is +, and it never uses a computed result&nbsp; <BR>&gt; more 
than once, so if the right answer is (say) 350 quintillion, it&nbsp; <BR>&gt; 
has to do around 350 quintillion "+" operations to add up to that&nbsp; <BR>&gt; 
answer.&nbsp; At a billion operations per second, that's eleven thousand&nbsp; 
<BR>&gt; years.&nbsp; (Interestingly enough, it only requires a stack depth of 
100,&nbsp; <BR>&gt; so stack overflow isn't a problem: if you can keep the 
computer&nbsp; <BR>&gt; running DrScheme for eleven thousand years without 
anybody tripping&nbsp; <BR>&gt; over the power cord or cosmic rays disrupting 
the RAM, it WILL&nbsp; <BR>&gt; produce the right answer.)<BR>&gt; <BR>&gt; John 
posted an alternative definition, using the technique of "memo- <BR>&gt; 
ization": in a nutshell, every time the function computes the answer&nbsp; 
<BR>&gt; to a question, it stores the answer in a table (indexed by the&nbsp; 
<BR>&gt; function input) so the next time it is asked the same question, 
it&nbsp; <BR>&gt; just re-uses the answer from the table rather than 
re-computing it.&nbsp;&nbsp; <BR>&gt; All of that is happening behind the scenes 
in the "memoize" package,&nbsp; <BR>&gt; although you could easily write your 
own memoized version of the&nbsp; <BR>&gt; function.&nbsp; With this simple 
transformation, the algorithm becomes&nbsp; <BR>&gt; linear-time in n, so it 
takes approximately 100 "+" operations rather&nbsp; <BR>&gt; than 350 
quintillion.<BR>&gt; <BR>&gt; Here's another approach which doesn't require a 
look-up table.&nbsp; When&nbsp; <BR>&gt; you say "Fibonacci sequences", you're 
more right than you may&nbsp; <BR>&gt; realize: there is not ONE Fibonacci 
sequence but infinitely many,&nbsp; <BR>&gt; each sequence determined by a 
different first two elements.&nbsp; If you&nbsp; <BR>&gt; start with F(1)=1, 
F(2)=1, you get "the usual" Fibonacci sequence,&nbsp; <BR>&gt; but you can also 
start from F(1)=17, F(2)=-4 or any other starting&nbsp; <BR>&gt; place you 
wish.&nbsp; So we define<BR>&gt; <BR>&gt; ; fib : nat-num -&gt; nat-num<BR>&gt; 
<BR>&gt; (check-expect (fib 1) 1)<BR>&gt; (check-expect (fib 2) 1)<BR>&gt; 
(check-expect (fib 3) 2)<BR>&gt; (check-expect (fib 4) 3)<BR>&gt; (check-expect 
(fib 5) 5)<BR>&gt; (check-expect (fib 6) 8)<BR>&gt; <BR>&gt; (define (fib 
n)<BR>&gt;&nbsp;&nbsp; (general-fib 1 1 n))<BR>&gt; <BR>&gt; ; general-fib : num 
(prev2) num (prev1) nat-num(n)<BR>&gt; ; computes the n-th Fibonacci number in 
the sequence whose 1st and&nbsp; <BR>&gt; 2nd elements are prev2 and 
prev1<BR>&gt; <BR>&gt; (check-expect (general-fib 17 -4 1) 17)<BR>&gt; 
(check-expect (general-fib 17 -4 2) -4)<BR>&gt; (check-expect (general-fib 17 -4 
3) 13)<BR>&gt; (check-expect (general-fib 17 -4 4) 9)<BR>&gt; (check-expect 
(general-fib 17 -4 5) 22)<BR>&gt; <BR>&gt; Now, how to define this?&nbsp; 
Consider the sequence starting with the&nbsp; <BR>&gt; numbers x and y, then 
chop off the first number.&nbsp; You still have a&nbsp; <BR>&gt; Fibonacci 
sequence, but now it starts with y and x+y, and the nth&nbsp; <BR>&gt; element 
of the old sequence is the n-1-th element of the new&nbsp; <BR>&gt; 
sequence.&nbsp; This gives us a natural recursive definition:<BR>&gt; <BR>&gt; 
(define (general-fib prev2 prev1 n)<BR>&gt;&nbsp;&nbsp; (cond [(&lt;= n 1) 
prev2]<BR>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [(= n 2) 
prev1]<BR>&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [else 
(general-fib prev1 (+ prev2 prev1) (- n 1))]))<BR>&gt; <BR>&gt; This version 
turns out to be much more efficient (all times are in&nbsp; <BR>&gt; 
milliseconds):<BR>&gt;&nbsp;&gt; (time (fib 10))<BR>&gt; cpu time: 3 real time: 
4 gc time: 0<BR>&gt; 55<BR>&gt;&nbsp;&gt; (time (fib 100))<BR>&gt; cpu time: 4 
real time: 5 gc time: 0<BR>&gt; 354224848179261915075<BR>&gt;&nbsp;&gt; (time 
(fib 1000))<BR>&gt; cpu time: 34 real time: 49 gc time: 0<BR>&gt; 
434665576869374564356885276750406258025646605173717804024817290895365554 
<BR>&gt; 
179490518904038798400792551692959225930803226347752096896232398733224711 
<BR>&gt; 
61642996440906533187938298969649928516003704476137795166849228875<BR>&gt; 
<BR>&gt; <BR>&gt; Moral of the story: sometimes generalizing the problem makes 
it&nbsp; <BR>&gt; easier to solve.<BR>&gt; <BR>&gt; Stephen Bloch<BR>&gt; 
</FONT><A href="mailto:sbloch@adelphi.edu"><FONT face="Courier New" 
size=2>sbloch@adelphi.edu</FONT></A><BR><FONT face="Courier New" size=2>&gt; 
<BR>&gt; <BR>&gt; <BR>&gt; 
_________________________________________________<BR>&gt;&nbsp; For list-related 
administrative tasks:<BR>&gt;&nbsp; </FONT><A 
href="http://list.cs.brown.edu/mailman/listinfo/plt-scheme"><FONT 
face="Courier New" 
size=2>http://list.cs.brown.edu/mailman/listinfo/plt-scheme</FONT></A></BODY></HTML>