(define -ayalog '())

括弧に魅せられて道を外した名前のないプログラマ

SICPを読む_(4)1章_手続きによる抽象の構築(p14)

問題1.6(p14)

とりあえずnew-ifを書いてみる。

(define (square x)
  (* x x))

(define (abs x)
  (if (> x 0)
      x
      (- x)))

(define (new-if predicate then-clause else-clause)
  (cond (predicate then-clause)
	(else else-clause)))

(define (sqrt-iter guess x)
  (new-if (good-enough? guess x)
      guess
      (sqrt-iter (improve guess x)
		 x)))

(define (improve guess x)
  (average guess (/ x guess)))

(define (average x y)
  (/ (+ x y) 2))

(define (good-enough? guess x)
  (< (abs (- (square guess) x)) 0.001))

(define (sqrt x)
  (sqrt-iter 1.0 x))

こんな感じ。
そのまま、これを実行する。

(sqrt 9)

いい感じに無限ループに陥る。
前までの頁に書いてあったけど、ifやcondは特殊形式なので述語(predicate)が真を返した段階で評価をやめて値を返しますよっと。
なので、new-ifを実装したことにより、本来評価されないelseが評価されてしまって無限ループなんですねー。
なるほど、と思いました。*1

問題1.7(p14)

考えてもよく分からなかった。。。
なのでこちらを参考にさせてもらいながら、解いてみることにする。(参考というか既に答えですが)

つまり、1.1.7のNewton法の解き方のままだと、非常に小さい値の場合に不正確な値が出て非常に大きい値の場合には近似値に途中で近づかなくなるので無限ループになると。。

ある繰返しから次へのguessの変化に注目し、変化が予測値に比べ非常に小さくなった時に止めるのである。

なので、good-enough?を以下のように書き換えればok。

;; (define (good-enough? guess x)
;;   (< (abs (- (square guess) x)) 0.001))
(define (good-enough? guess x)
  (< (abs (- guess (improve guess x))) 0.001))

問題1.8(p14)

よりよい近似値を求める式(improve)を立方根用に組み替えただけっていう印象。
基本的な考え方は変わらない。

(define (square x)
  (* x x))

(define (cbrt x)
  (cbrt-iter 1.0 x))

(define (cbrt-iter guess x)
  (if (good-enough? guess x)
      guess
      (cbrt-iter (improve guess x)
		 x)))

(define (improve guess x)
  (/ (+ (/ x (square guess)) (* 2 guess)) 3))

(define (good-enough? guess x)
  (< (abs (- guess (improve guess x))) 0.001))  

とりあえず一旦ここまで…。

*1:[Twitter:@valvallow]さんに教えてもらったけど、マクロならnew-ifを書くことができるそうです。何それ凄い。