問題1.7

  1. 1.1.7節で作成した、sqrtの弱点を解析せよ
  2. また、その弱点を改良せよ

とりあえず、検証用手続きを作る

(define (sqrt-test x)
  (/ (square (sqrt x)) x))

非常に小さい数の場合、閾値よりも小さい数になると精度が悪くなる。
再帰が少ない回数で終了してしまうため

(sqrt-test 0.001)
==> 1.70118517210756

(sqrt-test 0.0001)
==> 10.4383583352337

非常に大きい数の場合、何回繰り返しても目標閾値に達成しないため、
無限ループに陥る

(sqrt-test 10000000000000)
==>無限ループ


改良版good-enough?

; 変化率が一定以下になればOK
(define (good-enough? guess x)
  (< (change-rate guess x) 0.001))

; 現在の予測値との変化率を求める
(define (change-rate guess x)
  (/ (change-value guess x) guess))

; 変化量を求める
(define (change-value guess x)
  (abs (- guess (improve guess x))))

ばっちり

(sqrt-test 0.001)
; 1.00121716823195

(sqrt-test 0.0001)
; 1.00014281284086

(sqrt-test 10000000000000)
; 1.00009859407248

(sqrt-test 100000000000000000)
; 1.00000505272809

もちろんAnswerBookはより素敵な回答。

自分のはgood-enough?の引数を変えずに頑張っているため、improveが再帰一回に付き2回呼ばれてしまっている。
AnswerBookはsqrt-iterの引数を3つにすることで、improveが一回で済むようになり、かつ全体の構造もすっきりしている。