The lisp-way to solve Fibonnaci

前端 未结 14 1471
别那么骄傲
别那么骄傲 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 07:47

    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)
    
    0 讨论(0)
  • 2021-02-08 07:57

    ;;; 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

    0 讨论(0)
  • 2021-02-08 07:59

    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:

    • filter
    • fold

    Regarding other Lisp resources:

    • Common Lisp—On Lisp
    • Scheme—Structure and Interpretation of Computer Programs

    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))))
    
    0 讨论(0)
  • 2021-02-08 08:01
    (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.

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

    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:

    1. Use an iterative approach.
    (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)))
    
    1. Use Memoization. This means remembering the values see before and recalling them rather than recalculating them. The article provides a CL package that will do this as well as some code to do it yourself.
    0 讨论(0)
  • 2021-02-08 08:01
    (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)))
    
    0 讨论(0)
提交回复
热议问题