問題1-35〜39

今日は、不動点探索ロジックを使う問題に取り組みました。今回は、喫茶店で紙にロジックを書き出してから、家で実際にコードを書いてみました。大筋のロジックに間違いはありませんでしたが、細かい点でのミスが目立ち、なかなか思うような結果が返ってこなかったケースもありました。
まずは、問題1-35です。黄金比をfixed-pointを使って算出するロジックです。

(define tolerance 0.00001)

(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 (golden)
  (fixed-point (lambda (x) (average x (+ 1 (/ 1 x))))
               1.0))

(golden)
(/ 1 (golden))

=>1.6180311591702674
=>0.6180350695550287

問題1-37から登場する「連分数」には今回初めて出会いました。こんな数式の結果と、黄金比の逆数などと近似してしまうというのは不思議なものです。再帰的プロセスと反復的プロセスを考えたときに、上から計算していくのか、下から計算していくのかという点で若干混乱してしまい、予想以上に手こずってしまいました。

(define (cont-frac n d k)
  (define (iter i)
    (if (= i k)
        (/ (n i) (d i))
        (/ (n i) (+ (d i) (iter (+ i 1))))))
  (iter 1))

(cont-frac (lambda (i) 1.0)
           (lambda (i) 1.0)
           100)

=>0.6180339887498948
(define (cont-frac n d k)
  (define (iter i result)
    (if (= i 0)
        result
        (iter (- i 1) (/ (n i) (+ (d i) result)))))
  (iter k 1))

kを1から順に調べて、4桁の精度の近似を得る手続きも書いてみましたが、意味不明な構文エラーが出てしまい、結局原因を突き止められませんでしたので断念しました。無念です。
問題1-38は、以下のように書きました。

(cont-frac (lambda (i) 1.0)
           (lambda (i)
             (if (= (remainder i 3) 2)
                 (* (/ (+ i 1) 3) 2)
                 1.0))
           100)

=>0.7182818284590453

最後の問題1-39は次の通りです。

(define (tan-cf x k)
  (cont-frac (lambda (i) 
               (if (= i 1)
                   x
                   (* -1.0 x x)))
             (lambda (i) (- (* i 2) 1))
             k))

(tan-cf 90 1000)
(tan 90)

=>-1.9952004122082423
=>-1.995200412208242

自分のコードを眺めてみると、四則演算がいくつか続いている箇所でも改行しないで書いてしまう癖があることに気づきます。一文字だけのために改行すると、かえって見にくくなるのではないかとも思いますが、ある程度の長さになるのだったら改行した方が見やすいだろうというのが、現時点での実感です。