Gauche
SICP

SICP読書女子会 #11,12 1.4.6 返り値としての手続き まとめ

More than 1 year has passed since last update.

オンラインSICP読書女子会 #12 (1.3.4)

1.40 newton法

(load "./newtons-method.scm")
(define (cube x) (* x x x))

; 不動点プロセスで x^3 + a*x^2 + b*x + c = 0 の零点の近似値を求める
(define (cubic a b c)
  (lambda (x) (+ (cube x)
         (* a (square x))
         (* b x)
         c)))

(newtons-method (cubic -3 3 -1) 1) ;1.0

1.41 手続きを二回適用する手続き

(define (inc x) (+ x 1))

(define (double f)
  (lambda (x) (f (f x))))

((double inc) 1) ; 3
(((double (double double)) inc) 5) ; 21 (+16)

1.42

関数の合成を実装する手続きをcomposeを実装する

x -> f(g(x))

;; 1.42

(define (compose f g)
  (lambda (x) (f (g x)) ))

(define (square x) (* x x))
(define (inc x) (+ x 1))
((compose square inc) 6) ;; 49
((compose square inc) 11) ;; 144

1.43

n回fを適用する手続き repeatedを

fがsquareだったら、n回適用すれば引数を2^nする関数になる
f(f(......f(x)))

;; 1.43
(load "./1.42.scm")
(define (inc x) (+ x 1))

(define (repeated func n)
  (if (= n 1)
      func
      (compose func (repeated func (- n 1)))))


((repeated square 2) 5) ;; 625
(time ((repeated inc 10000000) 1))
; real   0.558
; user   0.550
; sys    0.000

;; hioさんの見習う

(define (repeated func n)
  (cond ((= n 1)
     func)
    ((= (remainder n 2) 1)
     (compose func (repeated func (- n 1))))
    (else
     (let ((f (repeated func (/ n 2))))
       (compose f f)))
    ))

((repeated square 2) 5) ;; 625
(time ((repeated inc 10000000) 1))
; real   0.552
; user   0.540
; sys    0.000


;; hioさんの末尾再帰版
(define (repeated f n)
  (define (iter i val)
    (if (>= i n)
    val
    (iter (+ i 1) (f val))))
  (lambda (x) (iter 0 x)))
(time ((repeated inc 10000000) 1))
; real   0.476
; user   0.480
; sys    0.000
;; そんな時間かわらないな
;; これだと手続き

1.44

平滑化: dxが小さな値であるとき、 f(x - dx), f(x), f(x + dx) の平均をとったもの
平滑化したものを計算するsmoothの手続きをかけ。
また、n重平滑化関数をrepeatedを使って示す。

;; 1.44
(load "./1.43.scm")

(define (smooth f)
  (define dx 0.0001)
  (lambda (x)
    (/ (+ (f (- x dx)) (f x) (f (+ x dx))) 3) ))

((smooth square) 2) ;; 4.000000006666666

(define (n-fold-smooth f n)
  (repeated (smooth f) n))

((n-fold-smooth square 4) 2) ;; 65536.00098646007 (2 ^ 16)

1.45 (未解決)

n乗根を求める

source

;; fixed-point
(define tolerance 0.0001)
(define max-recursion 8)
(define (fixed-point f first-guess)
  (define (close-enough? v1 v2)
    (< (abs (- v1 v2)) tolerance))

  (define (try guess i)
    (print "guess:" i "回目 " guess)
    (let ((next (f guess)))
      (if (or (close-enough? guess next) (= i max-recursion))
      next
      (try next (+ i 1)))))
  (try first-guess 1))

(define (average-damp f)
  (lambda (x) (/ (+ (f x) x) 2.0)))


;; 2, 3乗根
(define (nth-root x n)
  (fixed-point
   (average-damp (lambda (y) (/ x (expt y (- n 1))))) 1.0))

;;(print (nth-root 100 2)) ;;10.0
;;(print (nth-root 1000 3)) ;; 10.000002544054729
;; (nth-root 10000 4) ;;無限にfixせず、、、、


;; 4乗根以上
(define (repeated func n)
  (if (= n 1)
      func
      (compose func (repeated func (- n 1)))))

(define (repeated-nth-root x n m)
  (fixed-point
   (repeated (average-damp (lambda (y) (/ x (expt y (- n 1))))) m) 1.0))

(define (try-repeat m n root)
  (define (iter i)
    (print "----------------------------------")
    (print  m " ^ 1 / " root " の" i "重平均緩和")
    (print "----------------------------------")
    (repeated-nth-root m (+ i 1) root)
    (if (= i n)
    0
    (iter (+ i 1))))
  (iter 1))

(print "2のn乗のn乗根をしらべる")

(print "==========================")
(print "2乗根")
(print "==========================")
(try-repeat (expt 2 2) 3 2)

(print "==========================")
(print "3乗根")
(print "==========================")
(try-repeat (expt 2 3) 5 3)

(print "==========================")
(print "4乗根")
(print "==========================")
(try-repeat (expt 2 4) 5 4)

(print "==========================")
(print "5乗根")
(print "==========================")
(try-repeat (expt 2 5) 10 5)

結果

2のn乗のn乗根をしらべる

==========================
2乗根
==========================
----------------------------------
4 ^ 1 / 2 の1重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 2.05
guess:3回目 2.0000000929222947
----------------------------------
4 ^ 1 / 2 の2重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 1.57
guess:3回目 1.5829814190634435
guess:4回目 1.586291563873137
guess:5回目 1.5871233896905939
guess:6回目 1.5873316181944288
----------------------------------
4 ^ 1 / 2 の3重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 1.3780000000000001
guess:3回目 1.3781971576084833
guess:4回目 1.3783910746470118
guess:5回目 1.3785818395983083
guess:6回目 1.3787695375836293
guess:7回目 1.3789542505257217
guess:8回目 1.3791360573022022
==========================
3乗根
==========================
----------------------------------
8 ^ 1 / 3 の1重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 2.843780727630285
guess:3回目 2.82842712474619
----------------------------------
8 ^ 1 / 3 の2重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 1.8914996576441667
guess:3回目 2.0151199754332096
guess:4回目 1.998142301706526
guess:5回目 2.0002326972862416
guess:6回目 1.999970920454376
----------------------------------
8 ^ 1 / 3 の3重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 1.478337540623817
guess:3回目 1.9239087525290877
guess:4回目 1.5363162465727038
guess:5回目 1.8553689987180662
guess:6回目 1.560512615640326
guess:7回目 1.8244440279220622
guess:8回目 1.575115962052684
----------------------------------
8 ^ 1 / 3 の4重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 1.28327359906296
guess:3回目 2.227954293124733
guess:4回目 1.2615306050241493
guess:5回目 2.1609515864967843
guess:6回目 1.2706420422133782
guess:7回目 2.192947191071957
guess:8回目 1.2662518335488215
----------------------------------
8 ^ 1 / 3 の5重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 1.1951167859192295
guess:3回目 2.2691905546161637
guess:4回目 1.1778909647032938
guess:5回目 2.025355582188155
guess:6回目 1.393915404078827
guess:7回目 1.6030012367264348
guess:8回目 1.2279607772464904
==========================
4乗根
==========================
----------------------------------
16 ^ 1 / 4 の1重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 4.002257524798522
guess:3回目 4.0
----------------------------------
16 ^ 1 / 4 の2重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 2.4829963306881875
guess:3回目 2.5174777560877635
guess:4回目 2.5196940687432705
guess:5回目 2.519832846830349
----------------------------------
16 ^ 1 / 4 の3重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 1.8341723103276433
guess:3回目 1.8527375467627856
guess:4回目 1.8658611343368858
guess:5回目 1.875827463108303
guess:6回目 1.8837545613602775
guess:7回目 1.8902683221588625
guess:8回目 1.895752040837725
----------------------------------
16 ^ 1 / 4 の4重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 1.4493508391103145
guess:3回目 1.4519931178812753
guess:4回目 1.4536080602027628
guess:5回目 1.4545943546784106
guess:6回目 1.455195179157848
guess:7回目 1.4555603374021737
guess:8回目 1.4557818914922966
----------------------------------
16 ^ 1 / 4 の5重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 1.2475321803127808
guess:3回目 1.9040376089300204
guess:4回目 1.666016805952454
guess:5回目 3.1599408649420493
guess:6回目 1.4616166208630994
guess:7回目 1.5843404568698387
guess:8回目 1.540218409475213
==========================
5乗根
==========================
----------------------------------
32 ^ 1 / 5 の1重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 5.65697670118682
guess:3回目 5.65685424949238
----------------------------------
32 ^ 1 / 5 の2重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 3.2611793503277537
guess:3回目 3.1722582719630483
guess:4回目 3.1748817299345116
----------------------------------
32 ^ 1 / 5 の3重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 2.464263577716512
guess:3回目 2.3026699635645205
guess:4回目 2.460267138779624
guess:5回目 2.305728778345352
guess:6回目 2.4567770089373733
guess:7回目 2.3084377997602075
guess:8回目 2.4536947950137824
----------------------------------
32 ^ 1 / 5 の4重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 1.8527388808054341
guess:3回目 2.986203929953016
guess:4回目 1.684603068446882
guess:5回目 2.8502360866346947
guess:6回目 1.6695442360756085
guess:7回目 2.8887323780143497
guess:8回目 1.6735434538049703
----------------------------------
32 ^ 1 / 5 の5重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 1.4528868735679294
guess:3回目 3.435041945724486
guess:4回目 1.4526447052333216
guess:5回目 3.4265251637273857
guess:6回目 1.4336537993747493
guess:7回目 2.5063074888395556
guess:8回目 1.829979040239805
----------------------------------
32 ^ 1 / 5 の6重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 1.238771352270022
guess:3回目 1.8227353362149372
guess:4回目 1.9525400393432408
guess:5回目 4.780617424956585
guess:6回目 1.2363480996581633
guess:7回目 1.76652059151728
guess:8回目 1.4114961694924677
----------------------------------
32 ^ 1 / 5 の7重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 1.1321524709422879
guess:3回目 6.539943947950366
guess:4回目 1.466902719615096
guess:5回目 1.6646927417487603
guess:6回目 4.484304705092539
guess:7回目 1.4331808312190746
guess:8回目 1.8924176928951446
----------------------------------
32 ^ 1 / 5 の8重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 1.0801710623656842
guess:3回目 5.215018392022435
guess:4回目 3.2415512094000114
guess:5回目 1.5007653145374489
guess:6回目 5.542008185531579
guess:7回目 12.058755661446032
guess:8回目 2.143355616495691
----------------------------------
32 ^ 1 / 5 の9重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 1.0549588781203105
guess:3回目 2.114424633995316
guess:4回目 1.1136325618984133
guess:5回目 16.786757179080805
guess:6回目 9.27611486764099
guess:7回目 2.2729115607246606
guess:8回目 2.008299076235135
----------------------------------
32 ^ 1 / 5 の10重平均緩和
----------------------------------
guess:1回目 1.0
guess:2回目 1.0427412930632205
guess:3回目 1.3213126383907263
guess:4回目 8.168781903627231
guess:5回目 5.996862265689423
guess:6回目 6.317346815038818
guess:7回目 12.877405341365169
guess:8回目 29.6151176920096


  • 2乗根:1重平均緩和
    というのが最初にわかっていた内容

  • 3乗根:2重平均緩和(あれ、SICPによると1重平均緩和でできるはず・・・

  • 4乗根は、3重の平均緩和でそれらしい値になる (あれ、SICPによると2重平均緩和でできるはず・・・

  • 5乗根は無理じゃないか・・・

repeatのn回目nの数え方がおかしい?
わからなすぎてギブアップ\(^o^)/

1.46

十分になるまで改善を繰り返すような手続き(反復改良法)を返す手続き

(define (iterative-improve improve enough?)
  (lambda (guess)
    (define (iter guess)
      (if (enough? guess)
      guess
      (iter (improve guess))))
    (iter guess)))

;; sqrt
(define (sqrt x)
  (define (enough? guess)
    (< (abs (- (square guess) x)) 0.001))
  (define (improve guess)
    (average guess (/ x guess)))

  (define (average x y) (/ (+ x y) 2))
  ((iterative-improve improve enough?) 1.0))

(print "sqrt 2 = " (sqrt 2)) ;; 1.4142156862745097
(print "sqrt 4 = " (sqrt 4)) ;; 2.0000000929222947


;; fix-point
(define (fix-point f first-guess)
  (define (enough? guess)
    (< (abs (- guess (f guess))) 0.00001))
  (f ((iterative-improve f enough?) first-guess)))


;; golden ratio
(define (g x)
  (+ 1 (/ 1 x)))
(print "fix-point golden ratio = " (fix-point g 1.0)) ;;1.6180327868852458

参考 - 問題1.46 – SICP(計算機プログラムの構造と解釈)その24 : Serendip - Webデザイン・プログラミング
ga