5.1 圖就不畫在機器上了,麻煩
5.2 用寄存器語言描述5.1題中的階乘機器,加上了讀取和打印,這里的解答全部在實際的寄存機器中驗證過,但是仍然按照該節的表示法表示。
(controller
fac-loop
(assign n (op read))
(assign product (const 1))
(assign counter (const 1))
iter-loop
(test (op >) (reg counter) (reg n))
(branch (label iter-done))
(assign product (op *) (reg product) (reg counter))
(assign counter (op +) (reg counter) (const 1))
(goto (label iter-loop))
iter-done
(perform (op print) (reg product))
(goto (label fac-loop)))
5.3 牛頓法求平方根,將這個過程轉化為寄存器語言,第一個版本,假設good-enough?和improve都是基本過程,
;version1
(controller
sqrt-loop
(test (op good-enough?) (reg guess))
(branch (label sqrt-done))
(assign guess (op improve) (reg guess))
(goto (label good-enough))
sqrt-done)
第二個版本,展開good-enough?過程,
;version2
(controller
good-enough
(assign t (op square) (reg guess))
(assign t (op -) (reg t) (reg x))
(assign t (op abs) (reg t))
(test (op <) (reg t) (const 0.001))
(branch (label sqrt-done))
(assign guess (op improve) (reg guess))
(goto (label good-enough))
sqrt-done)
最后,展開improve過程,
;version3
(controller
sqrt-init
(assign guess (const 1.0))
(assign x (op read))
good-enough
;good-enough
(assign t (op square) (reg guess))
(assign t (op -) (reg t) (reg x))
(assign t (op abs) (reg t))
(test (op <) (reg t) (const 0.001))
(branch (label sqrt-done))
;improve
(assign t (op /) (reg x) (reg guess))
(assign t (op +) (reg guess) (reg t))
(assign guess (op /) (reg t) (const 2.0))
(goto (label good-enough))
sqrt-done)
在start之后,從寄存器guess中得到最后結果。
5.4
a)第一個是一個指數計算過程,用到了遞歸,因此需要引入continue寄存器來保存和恢復堆棧,實現與階乘相似,如下
(controller
(assign continue (label expt-done))
expt-loop
(test (op =) (reg n) (const 0))
(branch (label expt-base-case))
;;保存continue
(save continue)
(assign n (op -) (reg n) (const 1))
(assign continue (label after-expt))
(goto (label expt-loop))
after-expt
;;恢復continue
(restore continue)
(assign val (op *) (reg b) (reg val))
(goto (reg continue))
expt-base-case
(assign val (const 1))
(goto (reg continue))
expt-done
(perform (op display) (reg val)))
b) 迭代型的遞歸計算過程,尾遞歸調用,因此不需要continue寄存器來保存和恢復堆棧,這道習題就是希望能分辨非尾遞歸和尾遞歸帶來的寄存機器語言的區別
(controller
(assign product (const 1))
(assign n (op read))
(assign b (op read))
(assign counter (reg n))
expt-iter-loop
(test (op =) (reg counter) (const 0))
(branch (label expt-done))
(assign counter (op -) (reg counter) (const 1))
(assign product (op *) (reg b) (reg product))
(goto (label expt-iter-loop))
expt-done
(perform (op display) (reg product)))
5.5 手工模擬就算了,5.2節就可以機器模擬了
5.6 是有一個多余的save和一個多余的restore操作,請看注釋:
(
(assign continue (label fib-done))
fib-loop
(test (op <) (reg n) (const 2))
(branch (label immediate-answer))
;;compute fib(n-1)
(save continue)
(assign continue (label after-fib-1))
(save n)
(assign n (op -) (reg n) (const 1))
(goto (label fib-loop))
after-fib-1
;;compute fib(n-2)
(restore n)
;這里多余,(restore continue)
(assign n (op -) (reg n) (const 2))
;這里多余,(save continue)
(assign continue (label after-fib-2))
(save val) ;;save fib(n-1)
(goto (label fib-loop))
after-fib-2
(assign n (reg val))
(restore val)
(restore continue)
(assign val (op +) (reg val) (reg n))
(goto (reg continue))
immediate-answer
(assign val (reg n))
(goto (reg continue))
fib-done)