The lisp-way to solve Fibonnaci

前端 未结 14 1473
别那么骄傲
别那么骄傲 2021-02-08 07:17

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

相关标签:
14条回答
  • 2021-02-08 08:04

    My understanding of "the spirit of lisp" is to detach yourself from any fixed, dogmatic, stuckup idea of the spirit of lisp, and use the lisp construct that most closely reflects the structure of computation required to solve your problem. For example,

    (defun euler2 (&optional (n 4000000))
      (do ((i 1 j)
           (j 2 (+ i j))
           (k 0))
          ((<= n i) k)
        (when (evenp i) (incf k i))))
    

    If you insist on recursion, here is another way:

    (defun euler2 (&optional (n 4000000))
      (labels ((fn (i j k) 
                 (if (<= n i) k (fn j (+ i j) (if (oddp i) k (+ k i))))))
        (fn 1 2 0)))
    
    0 讨论(0)
  • 2021-02-08 08:05

    The way to solve this is to work bottom-up, generating each Fibonnaci term one-by-one, and adding it to the sum if it's even, and stopping once we reach the 4 million threshold. My LISP is rusty, so here it is in psuedocode:

    one_prior = 1
    two_prior = 1
    curr = 2
    sum = 0
    while curr < 4000000000
      if curr % 2 == 0
        sum = sum + curr
      two_prior = one_prior
      one_prior = curr
      curr = one_prior + two_prior
    
    0 讨论(0)
  • 2021-02-08 08:09

    danio's answer will help greatly with the performance questions.

    Here's a short critic of your style:

     (defun fib(i)
       (if (= i 1) ;//Could rewrite this as a case statement
         1
         (if (= i 2)
           1
           (+ (fib (- i 1)) (fib (- i 2)))
         )
       )
     )
    

    Refactor nested IFs into a COND.

    Don't put parentheses on a line by themselves.

     (defun solve(i)
       (let ((f (fib i))) ;//Store result in local variable
         (print f) ;//For debugging
         (if (
    
    

    Using ZEROP is clearer.

             (+ f (solve (+ i 1))) ;//add number
             (solve (+ i 1)) ;//Don't
    

    Why do you put those // in? A semicolon followed by a space is enough.

    ) ) ) ) (print (solve 1))

    You last PRINT statement makes me a bit suspicious. Are you running this program from a file or from the REPL? If you do the former then you should consider doing the latter. If you do the latter you can just say (solve 1) to get the result.

    0 讨论(0)
  • 2021-02-08 08:09

    Here is a memoised version. In this case, since you have to compute each fibonacci number until you find one more than four million, using closed form solutions would no do much good.

    This approach creates a lexical environment via let; create a dictionary fib-table and a function fib-memoed in that environment. The end product of this is fib-table is accesible from fib-memoed but no where else.

    Now the kicker: since we have to compute fib for sequential values until some condition is met, we start the solver at fib 1. From here on, computing the next fib number entails at most 2 dictionary lookups and one addition: O(1) BOOM!

    ;; memoised fib function: make a hash table, then create                                      
    ;; the fib function in the lexical scope of the hash table                                    
    (let ((fib-table (make-hash-table)))
      (setf (gethash 0 fib-table) 1)
      (setf (gethash 1 fib-table) 1)
      (defun fib-memoed (n)
        (let ((x (gethash n fib-table)))
          (cond ((not (null x))
                 x)
                (t
                 (let ((y (+ (fib-memoed (- n 1))
                             (fib-memoed (- n 2)))))
                   (setf (gethash n fib-table) y)
                   y))))))
    
    (defun solve ()
      (let ((maxval 4000000))
        (labels ((aux (i acc)
                   (let ((x (fib-memoed i)))
                     (cond ((> x maxval) acc)
                           ((evenp x)
                            (aux (1+ i) (+ x acc)))
                           (t (aux (1+ i) acc))))))
          (aux 1 0))))
    
    0 讨论(0)
  • 2021-02-08 08:10

    http://fare.tunes.org/files/fun/fibonacci.lisp has a walk through of solving fibonacci, gradually improving the time and memory performance of the implementation.

    0 讨论(0)
  • 2021-02-08 08:12

    See both the videos and text located at: http://groups.csail.mit.edu/mac/classes/6.001/abelson-sussman-lectures/

    0 讨论(0)
提交回复
热议问题