Search code examples
schemelispcomputation-theory

Can this function be simplified (made more "fast")?


I was wondering if this is the fastest possible version of this function.

(defun foo (x y)
  (cond 
   ;if x = 0, return y+1
   ((zp x) (+ 1 y)) 
   ;if y = 0, return foo on decrement x and 1
   ((zp y) (foo (- x 1) 1)) 
   ;else run foo on decrement x and y = (foo x (- y 1))
   (t (foo (- x 1) (foo x (- y 1)))))) 

When I run this, I usually get stack overflow error, so I am trying to figure out a way to compute something like (foo 3 1000000) without using the computer.

From analyzing the function I think it is embedded foo in the recursive case that causes the overflow in (foo 3 1000000). But since you are decrementing y would the number of steps just equal y?

edit: removed lie from comments


Solution

  • 12 years ago I wrote this:

    (defun ackermann (m n)
      (declare (fixnum m n) (optimize (speed 3) (safety 0)))
      (let ((memo (make-hash-table :test #'equal))
            (ncal 0) (nhit 0))
        (labels ((ack (aa bb)
                   (incf ncal)
                   (cond ((zerop aa) (1+ bb))
                         ((= 1 aa) (+ 2 bb))
                         ((= 2 aa) (+ 3 (* 2 bb)))
                         ((= 3 aa) (- (ash 1 (+ 3 bb)) 3))
                         ((let* ((key (cons aa bb))
                                 (val (gethash key memo)))
                            (cond (val (incf nhit) val)
                                  (t (setq val (if (zerop bb)
                                                   (ack (1- aa) 1)
                                                   (ack (1- aa) (ack aa (1- bb)))))
                                     (setf (gethash key memo) val)
                                     val)))))))
          (let ((ret (ack m n)))
            (format t "A(~d,~d)=~:d (~:d calls, ~:d cache hits)~%"
                    m n ret ncal nhit)
            (values ret memo)))))
    

    As you can see, I am using an explicit formula for small a and memoization for larger a.

    Note, however, that this function grows so fast that it makes little sense to try to compute the actual values; you will run out of atoms in the universe faster - memoization or not.