5.14 Exercise 5.14

We are asked to run the recursive factorial program through the interpreter with stack statistics enabled, deriving a formula for the relationship between n and the number of stack operations and the maximum depth of the stack during the execution of the program.

We should expect to see a linear relationship between both of these and the input size, because the program recurses by repeatedly subtracting one from the input. Let’s verify that.

First, here’s an instrumented version of the factorial program that initializes the stack at the beginning of the program and prints the stack statistics at the end:

(define recursive-factorial-machine
  (make-machine
    (list (list '= =) (list '- -) (list '* *))
    '(controller
       (perform (op initialize-stack))
       (assign continue (label fact-done))
       fact-loop
       (test (op =) (reg n) (const 1))
       (branch (label base-case))
       (save continue)
       (save n)
       (assign n (op -) (reg n) (const 1))
       (assign continue (label after-fact))
       (goto (label fact-loop))
       after-fact
       (restore n)
       (restore continue)
       (assign val (op *) (reg n) (reg val))
       (goto (reg continue))
       base-case
       (assign val (const 1))
       (goto (reg continue))
       fact-done
       (perform (op print-stack-statistics)))))

Next, let’s run the machine for the integers from 1 to 30:

(define (build-list n proc)
  (define (acc vals next)
    (if (> 0 next)
        vals
        (acc (cons (proc next) vals) (- next 1))))
  (acc '() (- n 1)))

> (for-each

    (lambda (n)

      (set-register-contents! recursive-factorial-machine 'n n)

      (start recursive-factorial-machine))

    (build-list 30 (lambda (i) (+ i 1))))

 

(total-pushes = 0 maximum-depth = 0)

(total-pushes = 2 maximum-depth = 2)

(total-pushes = 4 maximum-depth = 4)

(total-pushes = 6 maximum-depth = 6)

(total-pushes = 8 maximum-depth = 8)

(total-pushes = 10 maximum-depth = 10)

(total-pushes = 12 maximum-depth = 12)

(total-pushes = 14 maximum-depth = 14)

(total-pushes = 16 maximum-depth = 16)

(total-pushes = 18 maximum-depth = 18)

(total-pushes = 20 maximum-depth = 20)

(total-pushes = 22 maximum-depth = 22)

(total-pushes = 24 maximum-depth = 24)

(total-pushes = 26 maximum-depth = 26)

(total-pushes = 28 maximum-depth = 28)

(total-pushes = 30 maximum-depth = 30)

(total-pushes = 32 maximum-depth = 32)

(total-pushes = 34 maximum-depth = 34)

(total-pushes = 36 maximum-depth = 36)

(total-pushes = 38 maximum-depth = 38)

(total-pushes = 40 maximum-depth = 40)

(total-pushes = 42 maximum-depth = 42)

(total-pushes = 44 maximum-depth = 44)

(total-pushes = 46 maximum-depth = 46)

(total-pushes = 48 maximum-depth = 48)

(total-pushes = 50 maximum-depth = 50)

(total-pushes = 52 maximum-depth = 52)

(total-pushes = 54 maximum-depth = 54)

(total-pushes = 56 maximum-depth = 56)

(total-pushes = 58 maximum-depth = 58)

As predicted, there is a strict linear relationship between the number of pushes (and the maximum depth of the stack) and n – in this case, with the number of pushes and the maximum stack depth being 2 * (n - 1).