(sqrt-iter-cond 1 x)与(sqrt-iter-cond 1.0 x)的差

问题描述 投票:0回答:1

我阅读了答案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’

这里是什么问题?

elisp sicp
1个回答
2
投票

考虑使用两个整数调用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
© www.soinside.com 2019 - 2024. All rights reserved.