I wanted to try and learn Lisp, but I very quickly gave up. I figured I\'d try again. I\'m looking at Problem 2 on Project Euler - finding the sum of all even Fibonacci numbers
In addition to all useful answers, the following formulas may provide even more efficiency -- calculating Fn in O(Log(n)) instead of O(2^n). This has to be coupled with memoization, and is a solid base for solving the problem:
F(2*n) = F(n)^2 + F(n-1)^2
F(2*n + 1) = ( 2*F(n-1) + F(n) ) * F(n)
;;; I try to write code as suggestion of @PESTO
(defun Fibo-Test (n / one_prior two_prior curr sum i)
(setq i 2) (setq one_prior 1 two_prior 1 )
(cond
((= n 0) (setq sum 0) )
((= n 1) (setq sum 1) )
((= n 2) (setq sum 1) )
(T
(while (and (< i n) (< sum (* 4 1e6)))
;;; convert to Real-num
(setq sum (+ (float one_prior) (float two_prior)))
(setq i (1+ i))
(setq curr sum)
(setq
one_prior two_prior
two_prior curr
)
) ; end while
) ; end cond(T)
) ; end cond
(princ (strcat "\nF(" (itoa i) ") = " (RTOS sum) " . "))
(princ)
) ; end function Fibo-Test
Use tail recursion instead of naive recursion. Most Lisp implementations should perform the tailcall-optimization; no more recursion depth limit.
Beyond that, try to think of things in terms of lists and abstract operations you could perform on those lists. Two of the more relevant operations to consider:
Regarding other Lisp resources:
UPDATE:
Tail-recursive Scheme fib
function:
(define (fib n)
(fib-tr n 1 0))
(define (fib-tr n next result)
(cond ((= n 0) result)
(else (fib-tr (- n 1) (+ next result) next))))
(let ((a 1) (b 1))
(flet ((nextfib ()
(prog1 a
(psetf a b b (+ a b)))))
(loop for fib = (nextfib)
while (<= fib 4000000)
when (evenp fib)
sum fib)))
Above defines a function NEXTFIB which will generate the next fibonacci number for each call. The LOOP sums the even results upto the limit of 4000000.
PROG1 returns the value of the first of its subexpressions. PSETF sets a and b in 'parallel'.
That's a common pattern. There is a generator function and one calls it repeatedly, filters the results and combines them.
To expand on Danio's answer, the article at http://fare.tunes.org/files/fun/fibonacci.lisp presents two ways of making the code run faster. Using straight recursion (tail call or no) is O(2^n) and very slow. The difficulty is that each value gets calculated over and over again. You have to do things differently. The two recommendations are:
(defun bubble-fib (n) (declare (optimize (speed 3) (safety 0) (debug 0))) (check-type n fixnum) (loop repeat n with p = 0 with q = 1 do (psetq p q q (+ p q)) finally (return p)))
(defun fib (x &optional (y 0) (z 1))
(if (< x z)
nil
(append (list z) (fib x z (+ y z)))))
CL-USER> (reduce #'+ (remove-if-not #'evenp (fib 1000000)))