sicp(8)m2.6〜m2.11まで

問題2.11がとても時間かかった。

;;
;m2.6
(define zero (lambda (f) (lambda (x) x)))
(define (add-1 n)
  (lambda (f) (lambda (x) (f ((n f) x)))))
(define (inc x) (+ x 1))
;;コードから考えて使い方はこんな感じ。
;	gosh> ((zero inc) 1)
;	1
;;ということで、one,twoはたぶんこんな感じ。
(define one (lambda (f) (lambda (x) (f x))))
(define two (lambda (f) (lambda (x) (f (f x)))))
;	gosh> ((two inc) 2)
;	4
;;これでいいんじゃないかな?。
;;で、作りたいのはこんな感じのものだと思う。
;;(+ではなくaddにします。)
;	(((add one two) inc ) 3)
;	((three inc) 3)
;	6
(define (add f1 f2)
  (lambda (g) (lambda (x) ((f1 g) ((f2 g) x)))))
;	gosh> (((add (add one two) two) inc) 3)
;	8
;;できた!(昨日悩んだ甲斐があった)
;;addを作ってから、add-1の意味が分かった。
;; ;(add引く1じゃなくて、足す1の意味でした><)


;;2.1.4
(define (add-interval x y)
  (make-interval (+ (lower-bound x) (lower-bound y))
                 (+ (upper-bound x) (upper-bound y))))

(define (mul-interval x y)
  (let ((p1 (* (lower-bound x) (lower-bound y)))
        (p2 (* (lower-bound x) (upper-bound y)))
        (p3 (* (upper-bound x) (lower-bound y)))
        (p4 (* (upper-bound x) (upper-bound y))))
    (make-interval (min p1 p2 p3 p4)
                   (max p1 p2 p3 p4))))

(define (div-interval x y)
  (mul-interval x
                (make-interval (/ 1.0 (upper-bound y))
                               (/ 1.0 (lower-bound y)))))
;;m2.7
(define (make-interval a b)
  (cons a b))
(define (upper-bound z) (cdr z))
(define (lower-bound z) (car z))

;;m2.8
;;めんどうなので、抽象化
(define (op-interval op x y )
  (make-interval (op (lower-bound x) (lower-bound y))
                 (op (upper-bound x) (upper-bound y))))
(define (minus-interval x y)
  (op-interval - x y))

;;m2.9
(define (calc-width z)
  (/ (+ (upper-bound z) (lower-bound z)) 2))
;;問題の意味が分からなかったので調べました。
;;http://sicp.naochan.com/memo.pl?p=%CC%E4%C2%EA2.9
;;代替意味は分かりました。
;;めんどうなので(op = (+ or -))ということで話を進めます。
;;区間AとBの和(もしくは差)の幅がf(width(A),width(B)」
;;であることを示せばいいのだと思います。
;;width(A)と書くとめんどうなのでwaにします。
;	(op-interval A B)
;	(op-interval (cons la ua) (cons lb ub))
;	((op la lb) (op ua ub))
;;幅を計算
;	(calc-width (cons (op la lb) (op ua ub)))
;	(/ (+ (op la lb) (op ua ub)) 2)
;	(/ (op (+ la ua) (+ lb ub)) 2)
;	(op (/ (+ la ua) 2) (/ (+ lb ub) 2))
;	(op wa wb)
;;最終的に幅だけの関数になる
;	
;	;;乗算除算の時。(例だけでいいみたいなので例だけ)
(define (check f-interval a b)
  (display(calc-width (f-interval a b)))
  (display " = f(")
  (display (calc-width a))
  (display ", ")
  (display (calc-width b))
  (display ")"))
;	9 = f(7/2, 11/2) ;+
;	gosh> (check minus-interval (cons 3 4) (cons 5 6))
;	-2 = f(7/2, 11/2) ;-
;	gosh> (check mul-interval (cons 3 4) (cons 5 6))
;	39/2 = f(7/2, 11/2) ;*
;	gosh> (check div-interval (cons 3 4) (cons 5 6))
;	0.65 = f(7/2, 11/2) ;/

;;m2.10
;;単純に0を跨いでいるかどうか調べればいいっぽいので,
;;こんな感じかな?
(define (div-interval+check x y)
  (if (> 0 (* (lower-bound y) (upper-bound y)))
      (display "error!")
      (div-interval x y)))
;	(div-interval+check (cons 3 4) (cons -1 1))
;	error!#<undef>

;;m2.11
;;mul-intervalを9つの場合にわけることができる。
;;lower<upperなので
;	9=3*3
;	 =((--),(-+),(++))^2
;;これで9通り。
(define (mul-interval2 x y)
  (define (condition z do1 do2 do3)
    (cond ((and (< (lower-bound z) 0) (< (upper-bound z) 0)) do1) ;;--
          ((< (lower-bound z) 0) do2) ;-+
          (else do3))) ;++
  (let ((p1 (* (lower-bound x) (lower-bound y)))
        (p2 (* (lower-bound x) (upper-bound y)))
        (p3 (* (upper-bound x) (lower-bound y)))
        (p4 (* (upper-bound x) (upper-bound y))))
    (condition x
               (condition y
                          (make-interval p4 p1)
                          (make-interval p2 p1)
                          (make-interval p2 p3))
               (condition y
                          (make-interval p3 p1)
                          (make-interval (min p2 p3) (max p1 p4)) ;後でこっちに変更
                          ;(make-interval p2 p4) ;下の実験はこちらを使っている。
                          (make-interval p2 p4))
               (condition y
                          (make-interval p3 p2)
                          (make-interval p3 p4)
                          (make-interval p1 p4)))))

;;以下を使って調べた。
(define (search-mul-interval x y min-or-max)
  (let ((p1 (* (lower-bound x) (lower-bound y)))
        (p2 (* (lower-bound x) (upper-bound y)))
        (p3 (* (upper-bound x) (lower-bound y)))
        (p4 (* (upper-bound x) (upper-bound y))))
    (display (min-or-max p1 p2 p3 p4))
    (display ":  ")
    (display "lxly=")
    (display p1)
    (display ", lxuy=")
    (display p2)
    (display ", uxly=")
    (display p3)
    (display ", uxuy=")
    (display p4)))
(define f search-mul-interval)
(define x-- (cons -2 -1))
(define x-+ (cons -1 1))
(define x++ (cons 1 2))
(define y-- (cons -4 -3))
(define y-+ (cons -1 2))
(define y++ (cons 3 4))
;	gosh> (f x-- y-- min)
;	3:  lxly=8, lxuy=6, uxly=4, uxuy=3#<undef>
;	gosh> (f x-- y-+ min)
;	-4:  lxly=2, lxuy=-4, uxly=1, uxuy=-2#<undef>
;	gosh> (f x-- y++ min)
;	-8:  lxly=-6, lxuy=-8, uxly=-3, uxuy=-4#<undef>
;	gosh> (f x-+ y-- min)
;	-4:  lxly=4, lxuy=3, uxly=-4, uxuy=-3#<undef>
;	gosh> (f x-+ y-+ min)
;	-2:  lxly=1, lxuy=-2, uxly=-1, uxuy=2#<undef>
;	gosh> (f x-+ y++ min)
;	-4:  lxly=-3, lxuy=-4, uxly=3, uxuy=4#<undef>
;	gosh> (f x++ y-- min)
;	-8:  lxly=-4, lxuy=-3, uxly=-8, uxuy=-6#<undef>
;	gosh> (f x++ y-+ min)
;	-2:  lxly=-1, lxuy=2, uxly=-2, uxuy=4#<undef>
;	gosh> (f x++ y++ min)
;	3:  lxly=3, lxuy=4, uxly=6, uxuy=8#<undef>
;	gosh> "次はmax"
;	"次はmax"
;	gosh> (f x-- y-- max)
;	8:  lxly=8, lxuy=6, uxly=4, uxuy=3#<undef>
;	gosh> (f x-- y-+ max)
;	2:  lxly=2, lxuy=-4, uxly=1, uxuy=-2#<undef>
;	gosh> (f x-- y++ max)
;	-3:  lxly=-6, lxuy=-8, uxly=-3, uxuy=-4#<undef>
;	gosh> (f x-+ y-- max)
;	4:  lxly=4, lxuy=3, uxly=-4, uxuy=-3#<undef>
;	gosh> (f x-+ y-+ max)
;	2:  lxly=1, lxuy=-2, uxly=-1, uxuy=2#<undef>
;	gosh> (f x-+ y++ max)
;	4:  lxly=-3, lxuy=-4, uxly=3, uxuy=4#<undef>
;	gosh> (f x++ y-- max)
;	-3:  lxly=-4, lxuy=-3, uxly=-8, uxuy=-6#<undef>
;	gosh> (f x++ y-+ max)
;	4:  lxly=-1, lxuy=2, uxly=-2, uxuy=4#<undef>
;	gosh> (f x++ y++ max)
;	8:  lxly=3, lxuy=4, uxly=6, uxuy=8#<undef>

;;ここからは、check
(define (check-same?-mul-interval-1and2 x y)
  (if (and (= (car (mul-interval2 x y)) (car(mul-interval x y)))
           (= (cdr (mul-interval2 x y)) (cdr(mul-interval x y))))
      "ok!"
      "error!"))
(define g check-same?-mul-interval-1and2)
(define x-- (make-interval -7 -3))
(define x-+ (make-interval -5 13))
(define x++ (make-interval 2 11))
(define y-- (make-interval -32 -22))
(define y-+ (make-interval -22 22))
(define y++ (make-interval 20 50))
;;x-+ y-+のところだけ違うみたい。
;	gosh> (g x-- y--)
;	"ok!"
;	gosh> (g x-- y-+)
;	"ok!"
;	gosh> (g x-- y++)
;	"ok!"
;	gosh> (g x-+ y--)
;	"ok!"
;	gosh> (g x-+ y-+)
;	"error!"
;	gosh> (g x-+ y++)
;	"ok!"
;	gosh> (g x++ y--)
;	"ok!"
;	gosh> (g x++ y-+)
;	"ok!"
;	gosh> (g x++ y++)
;	"ok!"

;前回の結果
;;gosh> (f x-+ y-+ max)
;;2:  lxly=1, lxuy=-2(min), uxly=-1, uxuy=2(max)#<undef>
;今回の結果
;;gosh> (search-mul-interval x-+ y-+ max)
;;286:  lxly=110, lxuy=-110, uxly=-286(min), uxuy=286(max)#<undef>
;あとこんなのも
;;(search-mul-interval (cons -100 10) (cons -30 20) min)
;;-2000:  lxly=3000, lxuy=-2000, uxly=-300, uxuy=200#<undef>
;というわけで、x-+ y-+ のところを
;;(make-interval (min lxuy uxly) (max lxly uxuy))に変更!
;;これで完成。
;	gosh> (g x-+ y-+)
;	"ok!"
;	gosh> (g (cons -100 10) (cons -30 20))
;	"ok!"