sicp(5)m1.34〜m1.39

(更新したのは26日です。upするの忘れてました><)

;1.3.2
(define (sum term a b next)
  (if (> a b)
      0
      (+ (term a) (sum term (next a) b next))))
(define (integral f a b dx)
  (* (sum f
          (+ a (/ dx 2.0))
          b
          (lambda (x) (+ x dx)))
     dx))
	;;gosh> (integral (lambda (x) (* x x x)) 0 1 0.01)
	;;0.24998750000000042

(define (square x) (* x x))
(define (f x y)
  ((lambda (a b)
    (+ (* x (square a))
       (* y b)
       (* a b)))
  (+ 1 (* x y))
  (- 1 y)))
;;letを使うと↓のようになる。
(define (f2 x y)
  (let ((a (+ 1 (* x y)))
        (b (- 1 y)))
    (+ (* x (square a))
       (* y b)
       (* a b))))

;練習(本に書いてあるコードを写す)
(define boa 5)
(+ (let ((boa 3))
     (+ boa (* boa 10)))
   boa) ;=>38

;;m1.34
(define (f g)
  (g 2))
(f square)
;=> 4
(f (lambda (z) (* z (+ z 1))))
;=> 6

;どっちでも同じになった。
;;<1>作用的順序の場合
	;;(f f)
	;;(f 2)
	;;(2 2)
;;<2>正規順序の場合
	;;(f f)
	;;(f 2)
	;;(2 2)

;m1.3.3
(define (search f neg-point pos-point)
  (let ((midpoint (average neg-point pos-point)))
    (if (close-enogh? neg-point pos-point)
        midpoint
        (let ((test-value (f midpoint)))
          (cond ((positive? test-value)
                 (search f neg-point midpoint))
                ((negative? test-value)
                 (search f midpoint pos-point))
                (else midpoint))))))
(define (close-enogh? x y)
  (< (abs (- x y)) 0.001))

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

(define (half-interval-method f a b)
  (let ((a-value (f a))
        (b-value (f b)))
    (cond ((and (negative? a-value) (positive? b-value))
           (search f a b))
          ((and (negative? b-value) (positive? a-value))
           (search f b a))
          (else
           (error "Values are not of opposite sign" a b)))))
	;;(half-interval-method (lambda (x) (- (* x x x) (* 2 x) 3))
	;;                      1.0
	;;                      2.0) ;=> 1.89306640625

;;search-fixed-point(x=f(x)) -> (till enough? f(f(x))); fを増やす
(define tolerance 0.00001)

(define (fixed-point f first-guess)
  (define (close-enogh? v1 v2)
    (< (abs (- v1 v2)) tolerance))
  (define (try guess)
    (let ((next (f guess)))
      (if (close-enogh? guess next)
          next
          (try next))))
  (try first-guess))
	;;(fixed-point cos 1.0)
	;;=>0.8575532158463934

(define (sqrt x)
  (fixed-point (lambda (y) (/ x y)) 1.0)) ;;収束しないので無限ループ
	;; y=√x => y^2=x
	;;            y=x/y
	;;           2y=x/y +y
	;;            y=(y + x/y)/2 ;;average damping
(define (sqrt x)
  (fixed-point (lambda (y) (average y (/ x y))) 1.0))

;;m1.35
	;;θ=(1+√5)/2 =x->1+1/xの不動点
	;;(fixed-point (lambda (x) (+ 1 (/ 1 x))) 1.0)
	;;=>1.6666666666666665
	;;  ruby -e '(1+Math::sqrt(5))/2' =>1.61803398874989

;;m1.36
	;;y=x^x => logx(y)=x
	;;     ln(y)/ln(x)=x
	;;               x=ln(y)/ln(x)
;;fixed-pointを修正
(define (fixed-point f first-guess)
  (define (close-enogh? v1 v2)
    (< (abs (- v1 v2)) tolerance))
  (define (try guess count)
    (display count) (display " --- ") (display guess)
    (newline)
    (let ((next (f guess)))
      (if (close-enogh? guess next)
             next
             (try next (+ 1 count)))))
  (try first-guess 1))
	;;gosh> (fixed-point (lambda (x) (/ (log 1000) (log x))) 4)
	;;1 --- 4
	;;...
	;;29 --- 4.555530430629037
	;;4.555539183677709
;;平均緩和を使う。
	;;x=ln(y)/ln(x)
	;;x=(ln(y)/ln(x)+x)/2
	;;(define (average a b) (/ (+ a b ) 2))
	;;(fixed-point (lambda (x) (average x (/ (log 1000) (log x)))) 4)
	;;gosh> (fixed-point (lambda (x) (average x (/ (log 1000) (log x)))) 4)
	;;1 --- 4
	;;2 --- 4.491446071165521
	;;...
	;;7 --- 4.5555268862194875
	;;4.5555342036887705
;;m1.37
;(a.)
(define (cont-frac n d k)
  (define (f i)
    (let ((nk (n i))
          (dk (d i)))
      (if (= k i)
          (/ nk dk)
          (/ nk (+ (f (+ i 1)) dk)))))
    (f 1))
;;0側から数える方法しか思いつかなかった。
;!ruby -e 'x=Math::sqrt 5; y=(1+x)/2; p 1/y' #=>0.618033988749895
;!gosh> (cont-frac (lambda (i) 1.0) (lambda (i) 1.0) 10)
;!0.6180555555555556
;!gosh> (cont-frac (lambda (i) 1.0) (lambda (i) 1.0) 9)
;!0.6179775280898876
;;だから、きっと10

;(b.)
;;反復的な方
(define (inc i) (+ i 1))
(define (cont-frac2 n d k)
  (define (iter k result)
    (let ((nk (n k))
          (dk (d k)))
      (if (= 0 k)
          result
          (iter (- k 1) (/ nk (+ dk result))))))
  (iter k 0))
;;m1.38
(define (euler-e k)
  (+ (cont-frac2 (lambda (i) 1.0) next-d k)
     2))
;;next-dで問題の数列を作る
(define (next-d i)
  (let ((x (- i 2)))
        (let ((a (remainder x 3))
              (b (/ x 3)))
          (cond ((= i 1) 1)
                ((= i 2) 2)
                ((= a 0) (+ (* 2 b) 2 ))
                (else 1)))))
;;next-dのテスト用の関数
(define (f from to)
  (cond ((= from to) "done")
        (else
         (display (next-d from)) (display " ")
         (f (inc from) to))))
;!gosh> (f 1 20)
;!1 2 1 1 4 1 1 6 1 1 8 1 1 10 1 1 12 1 1 "done"
;;できているみたいなので、これを使って計算。
;!(euler-e 100)
;!2.7182818284590455

;;m1.39
(define (tan-cf x k)
  (define (n i)
    (if (= i 1)
        x
        ((lambda (n) (* n n)) x)))
  (define (d i)
    (- (* 2 i) 1))
  (cont-frac n d k))

;;再びm1.38
;![1,2,1],[1,4,1]と考えれば良いじゃないか。
(define (euler-e2 k)
  (define (d k)
    (if (= (remainder k 3) 2)
        (* 2 k)
        1))
 (+ 2 (cont-frac (lambda (i) 1.0) d k)))