SICPの問題を解こう 22
問題 1.45
n乗根を求めるのに y -> x/y^(n-1)のfixed-pointを計算していき差が少なくなった値を近似値とする方法において、y -> x/y^(n-1)にaverage dampingを何回行えばそれが収束するかという問題。
解析的に気になったのでSICP問題を解いているブログ界隈で探したけど記述があまりなかったので考察してみました。
解析
k乗根のfixed-pointを求める変換式 y -> x / y^(k-1) においてaverage damping をm重回行った変換を考え、その変換式をn回行った後の値をと置く。 この時は最初に与える値である。 が収束するとして収束値をと置き、におけるとの誤差をと置く。 はaverage dampingをm回行った変換式であるので以下の関係が成り立つ ここでが収束するとするならば、nが十分大きい時は収束値に比べて 十分小さくなるのでの2次以上の項は無視をした以下の近似式が成り立つ。 ※最後の等式でを使用した。 これよりは以下のように近似出来る ※最後の等式でを使用。 また、より ※先ほどの近似式を利用 となるのでについての漸化式 が得られる。が収束するためにはが0に収束する必要があり、その条件は上記漸化式より となる。この右側の不等号はより常に成り立つので左側の不等号を考えると すなわち という条件が得られる。 考察終わり。(mは整数なので m = が求める整数値ですね)
コード
(define (repeated f count) (if (= count 1) (lambda (x) (f x)) (lambda (x) (f ((repeated f (- count 1)) x))))) (define (fixed-point f guess) (let ((next (f guess))) (if (close-enough? guess next) next (fixed-point f next)))) (define (close-enough? a b) (define tolerance 0.0001) (print a " " b) (< (abs (- a b)) tolerance)) (define (average-damp f) (lambda (x) (/ (+ x (f x)) 2))) (define (expr x n) (if (= n 1) x (* x (expr x (- n 1))))) (define (nth-root x n k) (fixed-point ((repeated average-damp k) (lambda (y) (/ x (expr y (- n 1))))) 2.0)) (print (nth-root 10 2 1)) (print (nth-root 10 3 1)) ;(print (nth-root 10 4 1)) ;don't converge (print (nth-root 10 4 2)) ;(print (nth-root 10 8 2)) ;don't converge (print (nth-root 10 8 3))
問題 1.46
終了条件のチェックと次の改良値を算出する手続きの抽象化
(define (interative-improve f-enough f-improve) (lambda (guess x) (let ((next (f-improve guess x))) (if (f-enough guess next) next ((interative-improve f-enough f-improve) next x))))) (define tolerance 0.0001) (define (enough a b) (print a " " b) (< (abs (- a b)) tolerance)) (define (improve-sqrt guess x) (average guess (/ x guess))) (define (average a b) (/ (+ a b) 2)) (define (fixed-point f first-guess x) ((interative-improve enough f) first-guess x)) (define (sqrt first-guess x) ((interative-improve enough improve-sqrt) first-guess x)) (print (sqrt 1.0 2)) (print (fixed-point (lambda (y x) (/ (+ y (/ x y)) 2)) 1.0 2))
defineで引数を全て記述する場合はなんの迷いもなく書けるけど、lambdaをこんな感じで使おうとすると必ず失敗してちょっとづつ修正する事になる。。慣れるしか無さそう。
やっと1章終了。1ヶ月に数日思い出したようにやってただけだし、数学的に問題を解析してたから長いことかかった。。後4章終わらせるのに2年くらいかかるかも。