对于正文中的 good-enough? 谓词,设所求 x 的真实平方根为 xt,那么我们的依据是当 guess 从 1 趋向与 xt 的平方差 小于 c(0.001) 时,guess 近似于 xt。实际当 xt^2 也就是 x 足够小时, guess 会 逐渐稳定在 √c 附近。从下面实验可以看出:
> (sqrt (square 0.1))
0.10032578510960607
> (sqrt (square 0.05))
0.054237622808967656
> (sqrt (square 0.01))
0.03230844833048122
> (sqrt (square 0.005))
0.031515954454847304
> (sqrt (square 0.001))
0.031260655525445276
> (sqrt (square 0.0001))
0.03125010656242753
>
因为 guess^2 < c + x
, 当 x < c 时,guess 就更多的依赖于 c 了。
对于特别大的数,由于浮点数在特别大时,离散性非常明显,相邻的两个数之间的差距会非常大,导致 |guess^2 - x| 始终 大于 c,计算便进入了 无限循环。
比如计算 (sqrt 1e300)
使用变化率改进后的代码如下:
(define (sqrt-new x)
(sqrt-iter-new x 1.0 x))
(define (sqrt-iter-new s1 s2 x)
(if (enuf-new? s1 s2)
s2
(sqrt-iter-new s2 (improve s2 x) x)))
(define (enuf-new? s1 s2)
(< (/ (abs (- s1 s2)) s1) 0.001))
可以测算几个数,验证结果还是比较好的。
> (sqrt-new (square 1e150))
1.0000000000084744e+150
> (sqrt-new (square 1e-150))
1.0000000000084744e-150