SICP (16)
Ben の謎めいた発言のおかげ (でもないが) で進捗悪い。ってかわしのアタマが悪いんだろな。(とほほほ
問題 2.7
試験は略で実装を。
(define (lower-bound i) (car i)) (define (upper-bound i) (cdr i))
えーと、div-interval の実装の意味が最初分かってなかった。
(define (div-interval x y) (mul-interval x (make-interval (/ 1.0 (upper-bound y)) (/ 1.0 (lower-bound y)))))
最初、何故に upper と lower の位置を逆転させるのか、が意味不明だった。mul-interval する時に
- (* (lower-bound x) (lower-bound y))
- (* (lower-bound x) (upper-bound y))
- (* (upper-bound x) (lower-bound y))
- (* (upper-bound x) (upper-bound y))
の一番 {小さい, 大きい} ソレが所定の位置に設定されるんなら make-interval に渡すのはどっちでもいいじゃん、とかワケワカな感想を持っていたりなんかしていたんですが、一応 make-interval の作法に従っているんですね。小さい方が最初で大きい方が次、みたいな。(何故こんな感想を持ったか、というと問題 2.11 が悪い
ってか、分子が同じ値なら分母が大きい方が値としては小さくなる、という常識が (以下[略
問題 2.8
これも試験は略で。
(define (sub-interval x y) (make-interval (- (lower-bound x) (lower-bound y)) (- (upper-bound x) (upper-bound y))))
引いただけ。(を
ちなみに差の最小値は二つの下限 (lower-bound) の差で、最大値は二つの上限 (upper-bound) の差となる、で良いかな。
問題 2.9
スルーしたいんですが、例示の努力はしてみよう。
節の頭のサンプルの例で
gosh> i1 (6.12 . 7.48) gosh> i2 (4.465 . 4.935) gosh>
という二つの区間を用意して、まず加算。
gosh> (add-interval i1 i2) (10.585 . 12.415) gosh>
ちなみに許容誤差を無視した抵抗値は i1 は 6.8 オームで i2 は 4.7 オーム。この加算と add-intarval な値の平均を比較してみる。
gosh> (+ 6.8 4.7) 11.5 gosh> (/ (+ (lower-bound (add-interval i1 i2)) (upper-bound (add-interval i1 i2))) 2) 11.5 gosh>
あるいは減算。
gosh> (sub-interval i1 i2) (1.6550000000000002 . 2.545000000000001) gosh>
加算と同じ要領にて確認してみる。
gosh> (- 6.8 4.7) 2.0999999999999996 gosh> (/ (+ (lower-bound (sub-interval i1 i2)) (upper-bound (sub-interval i1 i2))) 2) 2.1000000000000005 gosh>
加算も減算もセンターな値からその両翼まできれいに区間の幅を表現している。対して乗算と除算について。まず乗算を。
gosh> (* 6.8 4.7) 31.96 gosh> (mul-interval i1 i2) (27.3258 . 36.9138) gosh> (/ (+ (lower-bound (mul-interval i1 i2)) (upper-bound (mul-interval i1 i2))) 2) 32.1198 gosh>
センターの値が微妙だが、これは誤差の範囲外だな。(って本当か??
除算も試してみます。
gosh> (/ 6.8 4.7) 1.4468085106382977 gosh> (div-interval i1 i2) (1.2401215805471126 . 1.6752519596864504) gosh> (/ (+ 1.2401215805471126 1.6752519596864504) 2) 1.4576867701167815 gosh>
むむむ、微妙かも。この問題はもう少し考えさせて下さひ。
問題 2.10
これは 0 divide と勝手読みしてがんがん進める。サンプルの div-interval は以下のように修正を。
(define (wrap-div-interval x y) (mul-interval x (make-interval (/ 1.0 (upper-bound y)) (/ 1.0 (lower-bound y)))))
で、以下を追加。
(define (div-interval x y) (cond ((= (lower-bound y) 0) (error "lower-y is zero")) ((= (upper-bound y) 0) (error "upper-y is zero")) (else wrap-div-interval x y)))
終わり方微妙かも。
問題 2.11
これ、苦労しました。mul-interval を要求されたソレで書いたのは test という手続きです。以下。
(define (test x y) (cond ;; x は全部正 ((>= (lower-bound x) 0) (cond ;; y は全部正 ((>= (lower-bound y) 0) ;; (* (lower-bound x) (lower-bound y)) が最小 ;; (* (upper-bound x) (upper-bound y)) が最大 (make-interval (* (lower-bound x) (lower-bound y)) (* (upper-bound x) (upper-bound y))) ) ;; y は全部負 ((< (upper-bound y) 0) ;; (* (upper-bound x) (lower-bound y)) が最小 ;; (* (lower-bound x) (upper-bound y)) が最大 (make-interval (* (upper-bound x) (lower-bound y)) (* (lower-bound x) (upper-bound y))) ) ;; y は片側のみ負 (else ;; (* (upper-bound x) (lower-bound y)) が最小 ;; (* (upper-bound x) (upper-bound y)) が最大 (make-interval (* (upper-bound x) (lower-bound y)) (* (upper-bound x) (upper-bound y))) )) ) ;; x は全部負 ((< (upper-bound x) 0) (cond ;; y は全部正 ((>= (lower-bound y) 0) ;; (* (lower-bound x) (upper-bound y)) が最小 ;; (* (upper-bound x) (lower-bound y)) が最大 (make-interval (* (lower-bound x) (upper-bound y)) (* (upper-bound x) (lower-bound y))) ) ;; y は全部負 ((< (upper-bound y) 0) ;; (* (upper-bound x) (upper-bound y)) が最小 ;; (* (lower-bound x) (lower-bound y)) が最大 (make-interval (* (upper-bound x) (upper-bound y)) (* (lower-bound x) (lower-bound y))) ) ;; y は片側のみ負 (else ;; (* (lower-bound x) (upper-bound y)) が最小 ;; (* (lower-bound x) (lower-bound y)) が最大 (make-interval (* (lower-bound x) (upper-bound y)) (* (lower-bound x) (lower-bound y))) )) ) ;; x は片側のみ負 (ってか、else で OK か) ; ((and (< (lower-bound x) 0) (>= (upper-bound x) 0)) (else (cond ;; y は全部正 ((>= (lower-bound y) 0) ;; (* (lower-bound x) (upper-bound y)) が最小 ;; (* (upper-bound x) (upper-bound y)) が最大 (make-interval (* (lower-bound x) (upper-bound y)) (* (upper-bound x) (upper-bound y))) ) ;; y は全部負 ((< (upper-bound y) 0) ;; (* (upper-bound x) (lower-bound y)) が最小 ;; (* (lower-bound x) (lower-bound y)) が最大 (make-interval (* (upper-bound x) (lower-bound y)) (* (lower-bound x) (lower-bound y))) ) ;; y は片側のみ負 (else ;; (min (* (lower-bound x) (upper-bound y)) ;; (* (upper-bound x) (lower-bound y))) が最小 ;; (max (* (upper-bound x) (upper-bound y)) ;; (* (lower-bound x) (lower-bound y))) が最大 (make-interval (min (* (lower-bound x) (upper-bound y)) (* (upper-bound x) (lower-bound y))) (max (* (upper-bound x) (upper-bound y)) (* (lower-bound x) (lower-bound y)))) )))))
なんか目がちかちかする。まだリファクタリングできそうだけど、このままで。
確認用の試験は以下です。
(define-test-case "(mul (+ +) (+ +)) test" ("mul test (1)" (let ((i1 (make-interval 1 2)) (i2 (make-interval 3 4))) (assert-equal (* (lower-bound i1) (lower-bound i2)) (lower-bound (test i1 i2))) (assert-equal (* (upper-bound i1) (upper-bound i2)) (upper-bound (test i1 i2))) ))) (define-test-case "(mul (+ +) (- -)) test" ("mul test (2)" (let ((i1 (make-interval 1 2)) (i2 (make-interval -3 -2))) (assert-equal (* (upper-bound i1) (lower-bound i2)) (lower-bound (test i1 i2))) (assert-equal (* (lower-bound i1) (upper-bound i2)) (upper-bound (test i1 i2))) ))) (define-test-case "(mul (+ +) (- +)) test" ("mul test (3)" (let ((i1 (make-interval 1 2)) (i2 (make-interval -3 1))) (assert-equal (* (upper-bound i1) (lower-bound i2)) (lower-bound (test i1 i2))) (assert-equal (* (upper-bound i1) (upper-bound i2)) (upper-bound (test i1 i2))) ))) (define-test-case "(mul (- -) (+ +)) test" ("mul test (4)" (let ((i1 (make-interval -2 -1)) (i2 (make-interval 1 2))) (assert-equal (* (lower-bound i1) (upper-bound i2)) (lower-bound (test i1 i2))) (assert-equal (* (upper-bound i1) (lower-bound i2)) (upper-bound (test i1 i2))) ))) (define-test-case "(mul (- -) (- -)) test" ("mul test (5)" (let ((i1 (make-interval -2 -1)) (i2 (make-interval -3 -2))) (assert-equal (* (upper-bound i1) (upper-bound i2)) (lower-bound (test i1 i2))) (assert-equal (* (lower-bound i1) (lower-bound i2)) (upper-bound (test i1 i2))) ))) (define-test-case "(mul (- -) (- +)) test" ("mul test (6)" (let ((i1 (make-interval -2 -1)) (i2 (make-interval -1 2))) (assert-equal (* (lower-bound i1) (upper-bound i2)) (lower-bound (test i1 i2))) (assert-equal (* (lower-bound i1) (lower-bound i2)) (upper-bound (test i1 i2))) ))) (define-test-case "(mul (- +) (+ +)) test" ("mul test (7)" (let ((i1 (make-interval -2 1)) (i2 (make-interval 1 2))) (assert-equal (* (lower-bound i1) (upper-bound i2)) (lower-bound (test i1 i2))) (assert-equal (* (upper-bound i1) (upper-bound i2)) (upper-bound (test i1 i2))) ))) (define-test-case "(mul (- +) (- -)) test" ("mul test (8)" (let ((i1 (make-interval -2 1)) (i2 (make-interval -4 -3))) (assert-equal (* (upper-bound i1) (lower-bound i2)) (lower-bound (test i1 i2))) (assert-equal (* (lower-bound i1) (lower-bound i2)) (upper-bound (test i1 i2))) ))) (define-test-case "(mul (- +) (- +)) test" ("mul test (9)" (let ((i1 (make-interval -3 1)) (i2 (make-interval -2 2))) (assert-equal (min (* (lower-bound i1) (upper-bound i2)) (* (upper-bound i1) (lower-bound i2))) (lower-bound (test i1 i2))) (assert-equal (max (* (upper-bound i1) (upper-bound i2)) (* (lower-bound i1) (lower-bound i2))) (upper-bound (test i1 i2))) ))) (define-test-case "(mul (- +) (- +)) test" ("mul test (10)" (let ((i1 (make-interval -1 3)) (i2 (make-interval -2 4))) (assert-equal (min (* (lower-bound i1) (upper-bound i2)) (* (upper-bound i1) (lower-bound i2))) (lower-bound (test i1 i2))) (assert-equal (max (* (upper-bound i1) (upper-bound i2)) (* (lower-bound i1) (lower-bound i2))) (upper-bound (test i1 i2))) )))
2.11 はまだ残りがあるな。
なるべく抽象的に検討を進めるべき、というソレに気づけば話は早いんですが、なかなかそれに気がつかない。
続きは別途。