我在理解 Common Lisp 函数的性能时遇到了问题(我还是个新手)。我有这个函数的两个版本,它只是计算所有整数的总和,直到给定的n
.
非尾递归版本:
(defun addup3 (n)
(if (= n 0)
0
(+ n (addup (- n 1)))))
尾递归版本:
(defun addup2 (n)
(labels ((f (acc k)
(if (= k 0)
acc
(f (+ acc k) (- k 1)))))
(f 0 n)))
我正在尝试使用输入在 CLISP 中运行这些函数n = 1000000
。这是结果
[2]> (addup3 1000000)
500000500000
[3]> (addup2 1000000)
*** - Program stack overflow. RESET
我可以在 SBCL 中成功运行两者,但非尾递归更快(只有一点点,但这对我来说似乎很奇怪)。我已经搜索了 Stackoverflow 问题的答案,但找不到类似的东西。尽管尾递归函数的设计目的不是将所有递归函数调用都放在堆栈上,但为什么会出现堆栈溢出?我是否必须告诉解释器/编译器优化尾调用?(我读过类似(proclaim '(optimize (debug 1))
设置调试级别并以跟踪能力为代价进行优化的内容,但我不知道这是做什么的)。也许答案很明显,代码是胡说八道,但我就是想不通。帮助表示赞赏。
编辑:danlei指出错字,它应该是addup3
第一个函数中的调用,所以它是递归的。如果更正,两个版本都会溢出,但不是他的
(defun addup (n)
"Adds up the first N integers"
(do ((i 0 (+ i 1))
(sum 0 (+ sum i)))
((> i n) sum)))
虽然这可能是一种更典型的方式,但我觉得奇怪的是尾递归并不总是优化的,考虑到我的导师喜欢告诉我它效率更高等等。