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