我阅读了答案https://stackoverflow.com/a/58899297/7301792,该答案通过迭代找到了sqrt
#+begin_src emacs-lisp :session sicp :lexical t
(defun sqrt-iter-cond(guess x)
(cond ((good-enough-p guess x) guess)
(t (sqrt-iter-cond (improve guess x) x))
)
)
(defun good-enough-p(guess x)
(< (abs (- (square guess) x)) 0.001))
(defun improve(guess x)
(average guess (/ x guess)))
(defun average(x y)
(/ (+ x y) 2))
(sqrt-iter-cond 1.0 13))
#+end_src
#+RESULTS:
: 3.6055513629176015
但是,如果将1.0更改为1,则会报告错误
#+begin_src emacs-lisp :session sicp :lexical t
(sqrt-iter-cond 1 13)
#+end_src
Lisp nesting exceeds ‘max-lisp-eval-depth’
这里是什么问题?
考虑使用两个整数调用average
函数和使用两个数字(其中一个或多个是浮点数)调用它之间的区别:
(average 3 4)
3
vs。
(average 3.0 4)
3.5
使用整数,您会陷入无限循环,因为improve
会调用average
,由于整数运算,最终会返回相同的整数值。但是对于浮点数,improve
实际上使猜测在每次调用时更接近结果,因为average
不限于仅返回整数。
解决此问题的一个简单方法是将average
函数更改为2.0而不是2:
(defun average(x y)
(/ (+ x y) 2.0))
如果将debug-on-error
设置为t
,则使用原始代码的回溯可以使您了解问题出在哪里:
Debugger entered--Lisp error: (error "Lisp nesting exceeds ‘max-lisp-eval-depth’")
(abs (- (* guess guess) x))
(< (abs (- (* guess guess) x)) 0.001)
good-enough-p(3 13)
(cond ((good-enough-p guess x) guess) (t (sqrt-iter-cond (improve guess x) x)))
sqrt-iter-cond(3 13)
(cond ((good-enough-p guess x) guess) (t (sqrt-iter-cond (improve guess x) x)))
sqrt-iter-cond(3 13)
(cond ((good-enough-p guess x) guess) (t (sqrt-iter-cond (improve guess x) x)))
sqrt-iter-cond(3 13)
...
...
表示回溯一直在重复。
或者,仅将message
调用添加到improve
函数中可以帮助:
(defun improve(guess x)
(message (format "guess: %f, x: %f" guess x))
(average guess (/ x guess)))
[使用原始的average
函数使用整数算术,*Message*
缓冲区显示:
guess: 4.000000, x: 13.000000
guess: 3.000000, x: 13.000000 [391 times]
使用浮点数,消息显示猜测值收敛到答案:
guess: 1.000000, x: 13.000000
guess: 7.000000, x: 13.000000
guess: 4.428571, x: 13.000000
guess: 3.682028, x: 13.000000
guess: 3.606345, x: 13.000000