Common Lisp: Why does my tail-recursive function cause a stack overflow? -
i have problem in understanding performance of common lisp function (i still novice). have 2 versions of function, computes sum of integers given n
.
non-tail-recursive version:
(defun addup3 (n) (if (= n 0) 0 (+ n (addup (- n 1)))))
tail-recursive version:
(defun addup2 (n) (labels ((f (acc k) (if (= k 0) acc (f (+ acc k) (- k 1))))) (f 0 n)))
i trying run these functions in clisp input n = 1000000
. here result
[2]> (addup3 1000000) 500000500000 [3]> (addup2 1000000) *** - program stack overflow. reset
i can run both in sbcl, non-tail-recursive 1 faster (only little, seems strange me). i've scoured stackoverflow questions answers couldn't find similar. why stack overflow although tail-recursive function designed not put recursive function calls on stack? have tell interpreter/compiler optimise tail calls? (i read (proclaim '(optimize (debug 1))
set debug level , optimize @ cost of tracing abilities, don't know does). maybe answer obvious , code bullshit, can't figure out. appreciated.
edit: danlei pointed out typo, should call addup3
in first function, recursive. if corrected, both versions overflow, not one
(defun addup (n) "adds first n integers" (do ((i 0 (+ 1)) (sum 0 (+ sum i))) ((> n) sum)))
while may more typical way it, find strange tail recursion not optimised, considering instructors tell me it's more efficient , stuff.
there no requirement common lisp implementation have tail call optimization. do, (i think abcl not, due limitations of java virtual machine).
the documentation of implementation should tell optimization settings should chosen have tco (if available).
it more idiomatic common lisp code use 1 of looping constructs:
(loop :for :upto n :sum i) (let ((sum 0)) (dotimes (i n) (incf sum (1+ i)))) (do ((i 0 (1+ i)) (sum 0 (+ sum i))) ((> n) sum))
in case, of course, better use "little gauß":
(/ (* n (1+ n)) 2)
Comments
Post a Comment