さかもとのブログ

つらつらと

SICP演習問題5.26, 5.27, 5.28

3問続いているけれど,やることは同じなのでまとめてしまう.

5.26
(define (factorial n)
  (define (iter product counter)
    (if (> counter n)
        product
        (iter (* product counter)
              (+ counter 1))))
  (iter 1 1))

を実行するときのスタックを監視せよという問題.
スタックの量はこのように表示される.

;; n = 5
(factorial 5)
;;; EC-Eval input:
(total-pushes = 204 maximum-depth = 10)

;;; EC-Eval value:
120

nが1~5を表にまとめる.

n total-pushed maximum-depth
5 204 10
4 169 10
3 134 10
2 99 10
1 64 10

maximum-depthが定数であることがわかる.
また,total-pushedは35n+29で表せるのでO(n)になる.(5.26のbの答え)

5.27

5.27では

(define (factorial n)
  (if (= n 1)
      1
      (* (factorial (- n 1)) n)))

のような再帰的プロセスを実行したときのスタックを監視せよという問題.
5.26と同様に表にまとめる.

n total-pushed maximum-depth
5 144 28
4 112 23
3 80 18
2 48 13
1 16 8

簡単な考察をすると,

  • 計算時間(tatal-pushes)に関して, 数字だけ見てみると,反復的(35n+29) > 再帰的(16(2n-1))であるが,どちらもO(n)である
  • メモリ容量(maximum-depth)に関しては,反復的なほうは定数(10)なのでO(1)であるのに対し,再帰的なほうは, 5n+3なのでのO(n)である
5.28

5.28では,評価器のev-sequenceを

ev-sequence
  (test (op no-more-exps?) (reg unev))
  (branch (label ev-sequence-end))
  (assign exp (op first-exp) (reg unev))
  (save unev)
  (save env)
  (assign continue (label ev-sequence-continue))
  (goto (label eval-dispatch))
ev-sequence-continue
  (restore env)
  (restore unev)
  (assign unev (op rest-exps) (reg unev))
  (goto (label ev-sequence))
ev-sequence-end
  (restore continue)
  (goto (reg continue))

として,評価器のなかに末尾再帰的でないものを組み込んだ場合にどうなるか,というもの.
それぞれ以下のようになる

  • 反復的
n total-pushed maximum-depth
5 218 29
4 181 26
3 144 23
2 107 20
1 70 17
  • 再帰的
n total-pushed maximum-depth
5 154 43
4 120 35
3 86 27
2 52 19
1 18 11

反復的プロセスが反復的でなくなってしまうことがわかる.