第11回SICP勉強会
内容
- 今回は問題ばっかり
問題
問題2.10
;; 問題2.10 ;; 0をまたがる区間で割った時、どうなるか分からないことを調べる (define R1 (make-interval 5 10)) (define R2 (make-interval 1 5)) (define R3 (make-interval -10 -5)) (define R4 (make-interval -5 10)) (div-interval R1 R2) ;; gosh> (1.0 . 10.0) ;; 期待通り (div-interval R1 R3) ;; gosh> (-2.0 . -0.5) ;; 期待通り (div-interval R1 R4) ;; gosh> (-2.0 . 1.0) ;; 期待通りではない ;; ほんとは(-1, 1)になってほしい ;; div-intervalはmul-intervalを利用していて ;; mul-intervalで全ての区間の組み合わせで ;; 乗算を行ったあと、大小関係を判定しているため (define (new-div-interval x y) (let ((ly (lower-bound y)) (uy (upper-bound y))) (if (< (* ly uy) 0) (error "error") (mul-interval x (make-interval (/ 1.0 ly) (/ 1.0 uy)))))) (new-div-interval R1 R2) ;; gosh> (1.0 . 10.0) (new-div-interval R1 R3) ;; gosh> (-2.0 . -0.5) (new-div-interval R1 R4) ;; gosh> *** ERROR: error ;; Stack Trace: ;; _______________________________________
問題2.11
;; 問題2.11 ;; 9つの場合分けは ;; 1. ux > 0, lx > 0 かつ uy > 0, ly > 0 ;; 2. ux > 0, lx > 0 かつ uy > 0, ly < 0 ;; 3. ux > 0, lx > 0 かつ uy < 0, ly < 0 ;; 4. ux > 0, lx < 0 かつ uy > 0, ly > 0 ;; 5. ux > 0, lx < 0 かつ uy > 0, ly < 0 ;; 6. ux > 0, lx < 0 かつ uy < 0, ly < 0 ;; 7. ux < 0, lx < 0 かつ uy > 0, ly > 0 ;; 8. ux < 0, lx < 0 かつ uy > 0, ly < 0 ;; 9. ux < 0, lx < 0 かつ uy < 0, ly < 0 ;; http://csnagoya-sicp.g.hatena.ne.jp/clairvy/20090411/sicp_ex_2_11 ;; 2回を超える乗算が必要なのは2の時? (define (new-mul-interval x y) (let ((ux (upper-bound x)) (lx (lower-bound x)) (uy (upper-bound y)) (ly (lower-bound y))) (cond [(and (> ux 0) (> lx 0)) (cond [(and (> uy 0) (> ly 0)) (make-interval (* ux uy) (* lx ly))] [(and (> uy 0) (< ly 0)) (make-interval (* ux uy) (* lx ly))] [(and (< uy 0) (< ly 0)) (make-interval (* ux ly) (* lx uy))])] [(and (> ux 0) (< lx 0)) (cond [(and (> uy 0) (> ly 0)) (make-interval (* ux uy) (* lx ly))] [(and (> uy 0) (< ly 0)) (make-interval (min (* ux ly) (* lx uy)) (max (* lx ly) (* ux uy)))] [(and (< uy 0) (< ly 0)) (make-interval (* lx ly) (* ux uy))])] [(and (< ux 0) (< lx 0)) (cond [(and (> uy 0) (> ly 0)) (make-interval (* lx uy) (* ux ly))] [(and (> uy 0) (< ly 0)) (make-interval (* lx ly) (* ux uy))] [(and (< uy 0) (< ly 0)) (make-interval (* ux uy) (* lx ly))])])))
問題2.12
;; 問題2.12 ;; 区間構成子 (define (make-interval a b) (cons a b)) ;; 選択子upper-bound, lower-boundの実装 (define (upper-bound x) (cdr x)) (define (lower-bound x) (car x)) ;; 中央値と許容誤差で表す数を扱う構成子と選択子 (define (make-center-width c w) (make-interval (- c w) (+ c w))) (define (center i) (/ (+ (lower-bound i) (upper-bound i)) 2)) (define (width i) (/ (- (upper-bound i) (lower-bound i)) 2)) ;; 中央値とパーセント許容誤差をとり、区間を返す構成子 (define (make-center-percent c p) (let ((per (/ p 100.0))) (make-interval (- c (* c per)) (+ c (* c per))))) (define (center i) (/ (+ (lower-bound i) (upper-bound i)) 2)) (define (percent i) (let ((width (/ (- (upper-bound i) (lower-bound i)) 2))) (* (/ width (center i)) 100))) ;; 10パーセントの許容誤差で6.8オーム(教科書P52) (define R1 (make-center-percent 6.8 10)) (display R1) ;; gosh> (6.12 . 7.479999999) (center R1) ;; gosh> 6.8 (percent R1) ;; gosh> 9.999999999999996 ;; なんか微妙に誤差が・・・
問題2.13
;; 問題2.13 ;; 参照 ;; http://csnagoya-sicp.g.hatena.ne.jp/clairvy/20090411/sicp_ex_2_13 ;; やりたいことはP(x × y) ≒ f(P(x), P(y))の形式で表現できることを示せ ;; という話 ;; 長くてここに書くのはきついので... ;; 基本的な考え方 ;; 2つの区間の双方ともに正の場合 ;; P(x × y) = (C(x × y) / W(x × y)) × 100 ;; x × y, C(x × y), W(x × y)を求める ;; C(x × y)を求めた結果にパーセント相対許容誤差が、 ;; 中央値より小さいという過程を適用する
問題2.14
;; 問題2.14 ;; http://csnagoya-sicp.g.hatena.ne.jp/clairvy/20090412/sicp_ex_2_14 (define (par1 r1 r2) (div-interval (mul-interval r1 r2) (add-interval r1 r2))) (define (par2 r1 r2) (let ((one (make-interval 1 1 ))) (div-interval one (add-interval (div-interval one r1) (div-interval one r2))))) ;; par1とpar2で結果が異なることの確認 (define R1 (make-center-percent 6.8 10)) (define R2 (make-center-percent 4.7 5)) (display R1) (display R2) (par1 R1 R2) ;; gosh> (2.201031010873943 . 3.4873689182805854) (par2 R1 R2) ;; gosh> (2.581558809636278 . 2.97332259363673) ;; 幅が中央値に比べて小さいパーセントの区間を用いて確認 (define R3 (make-center-percent 10 1)) (display R3) (define R4 (make-center-percent 20 1)) (display R4) (define div-R3 (div-interval R3 R3)) (center div-R3) ;; gosh> 1.0002000200020003 (percent div-R3) ;; gosh> 1.9998000199979908 ;; 誤差が1%から約2%へと増加している (define div-R3-R4 (div-interval R4 R3)) (center div-R3-R4) ;; gosh> 2.0004000400040005 (percent div-R3-R4) ;; gosh> 1.9998000199979908 ;; やはり誤差が増加している ;; 区間同士の乗算及び除算を行うと誤差が ;; 増加していくことが推察できる
問題2.15
;; 問題2.15 (define R3 (make-center-percent 10 1)) (define R4 (make-center-percent 20 1)) (define R5 (make-center-percent 10 3)) (define R6 (make-center-percent 10 0.1)) (define R7 (make-center-percent 1000 50)) (define (check-percent x y) (percent (div-interval x y))) ;; 引き続いて振る舞いについての観察 ;; 同一区間での除算の時の誤差 (check-percent R3 R3) ;; gosh> 1.9998000199979908 ;; 誤差が同じで中央値が異なる時の誤差 (check-percent R4 R3) ;; gosh> 1.9998000199979908 ;; 誤差の大きさが異なる時の誤差 (check-percent R5 R3) ;; gosh> 3.9988003598920248 ;; 誤差が大きく異なるときの誤差 (check-percent R7 R6) ;; gosh> 50.07496251874062 ;; 他の場合と比較して単純な誤差の和になっていない ;; 誤差の大きさが大きく異なる場合、小さい方の ;; 誤差の影響はほとんど無視出来るほど小さくなる ;; ことが予想される ;; 以上から、par1よりpar2のほうが「よい」プログラムであるというのは真である ;; なぜなら、par2は双方ともに区間を用いるのではなく、 ;; 片方の区間を定数(誤差0)にすることで相対誤差の増加を抑えているためである
問題2.16
;; 問題2.16 ;; 代数演算的にR1R2/(R1+R2)の分母と分子が同一のR1とは言えないようになってしまっているから ;; 代数的なアプローチは適当にWebを検索したら出てくる ;; 代数的なアプローチではない場合 ;; 構文解析をして、抵抗を計算するものは強制的に誤差の伝播が少ない形式にする ;; 代数変形するいくつかのパターンをあらかじめ用意しておいて、誤差の伝播が少ないパターン ;; で計算するとか
所感
- 問題2.16やってなかったというね
- 普通に頭がごちゃごちゃになりました・・・