LoginSignup
0
0

More than 5 years have passed since last update.

SICP読書録 #16 練習問題 1.43 - 練習問題 1.46

Posted at

hiroshi-manabe様の日本語訳を使わせてもらいます。
練習問題等はGaucheで実行。

前回はこちら

練習問題 1.43

手続きを指定した回数だけ適用する手続きrepeatedを実装する。
前回作成した、合成関数を生成する手続きcomposeが活用できる。

_.scm
(define (compose f g) (lambda (x) (f (g x))))

(define (repeated proc n)
  (if (= n 1)
    proc
    (compose proc (repeated proc (- n 1)))))

実行結果。

_.scm
gosh> ((repeated square 2) 5)
625

練習問題 1.44

平滑化とは、$f$が関数で$dx$が小さな値であるとき、$x$での値を$f(x-dx)$, $f(x)$, $f(x+dx)$の平均とすることをいう。これは、信号処理においてノイズを除去するために利用される手法だ。

手続きを受け取り、その平滑化関数を返す手続きsmoothを実装する。

_.scm
(define dx 0.0001)

(define (smooth proc)
  (lambda (x)
    (/ (+ (proc (+ x dx)) (proc x) (proc (- x dx))) 3)))

平滑化を繰り返し適用するn重平滑化関数というのが役に立つこともある。先のrepeatedを使えば簡単に実装できる。

_.scm
(define (n-smooth proc n)
  ((repeated smooth n) proc))

練習問題 1.45

1.3.3節で、$y\mapsto x/y$の不動点を探すことによって平方根を計算してみた。この際、平均緩和法によって解を収束できることも学んだ。

これは、n乗根の計算として一般化できる。$y\mapsto x/y^{n-1}$の不動点を探せばいいのだ。しかし例えば、$y\mapsto x/y^{3}$だと平均緩和法を1回行うだけでは収束しない。この場合は2回行えば収束する。

nの値が変わったときに必要な平均緩和法の回数を調べるため、以下の手続きを用意する。

_.scm
(define tolerance 0.00001)

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

(define (fixed-point f first-guess)
  (define (close-enough? v1 v2)
    (< (abs (- v1 v2))
      tolerance))
  (define (try guess)
    (let ((next (f guess)))
      (if (close-enough? guess next)
          next
          (try next))))
  (try first-guess))

(define (average-damp f)
  (lambda (x) (average x (f x))))

(define (n-root-test x n c)
  (fixed-point ((repeated average-damp c)
                  (lambda (y) (/ x (expt y (- n 1)))))
               1.0))

nを増やしながら、それぞれ収束するcの最小値を調べていくと。。。

_.scm
gosh> (n-root-test (expt 2 2) 2 1)
2.000000000000002
gosh> (n-root-test (expt 2 3) 3 1)
1.9999981824788517
gosh> (n-root-test (expt 2 4) 4 2)
...
gosh> (n-root-test (expt 2 16) 16 4)
2.000000000076957
...
gosh> (n-root-test (expt 2 32) 32 5)
2.000000000000006

こんな法則が見つかった。理屈は不明だけど、$log_2 n$を小数点以下切り捨てした回数だけ、平均緩和法を適用すればよい、らしい。

というわけで、以下のように一般化できた。

_.scm
(define (n-root x n)
  (fixed-point ((repeated average-damp (floor (/ (log n) (log 2))))
                  (lambda (y) (/ x (expt y (- n 1)))))
                1.0))

練習問題 1.46

今までやってきたことのいくつかは、反復改良法というものの例だ。つまり、推測値が十分よくなるまで改良を続ける、というプロセスである。これを抽象化しよう。

推測値が十分によいかを判断する手続きと、推測値を改良する手続きが与えられれば、反復改良法により近似値を探し出す手続き(これは初期推測値を引数として受け取る)を返す、という内容のiterative-improve手続きを実装しよう。

_.scm
(define (iterative-improve enough? improve)
  (define (iter guess)
    (if (enough? guess)
      guess
      (iter (improve guess))))
  (lambda (guess) (iter guess)))

これを使って、1.1.7節で実装したsqrt手続きを作り直してみる。

_.scm
(define tolerance 0.00001)
(define (average x y)
  (/ (+ x y) 2))

(define (sqrt x)
  (define (enough? guess)
    (< (abs (- (square guess) x)) tolerance))
  (define (improve guess)
    (average guess (/ x guess)))
  ((iterative-improve enough? improve) 1.0))

不動点を求める手続きfixed-pointも、同様に作り直してみる。

_.scm
(define (fixed-point f first-guess)
  (define (enough? guess)
    (< (abs (- guess (f guess))) tolerance))
  (define (improve guess)
    (f guess))
  ((iterative-improve enough? improve) 1.0))

これにて第1章おわり!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0