プログラマとプロマネのあいだ

プログラマもやるし、プロマネもやるし、たまに似非アーキとか営業っぽいこともやるITエンジニアがスキルアップの話を中心に日常を綴るブログです。

「Ansi Common Lisp」13章練習問題

1. 自分の使っているコンパイラがインライン宣言に対応しているかどうか確かめよ。

declareも、declaimも使えたので、対応しているのでしょう。

2. 以下の関数を末尾再帰に書き換えよ。コンパイルしたときどのぐらい速度が改善するか。

(defun foo (x)
  (if (zerop x)
    0
    (+ 1 (foo (1- x)))))
(defun foo (x)
  (if (zerop x)
    0
	(+ 1 (foo (1- x)))))

(defun foo-tail-recursion (x acc)
  (if (zerop x)
    acc
    (foo-tail-recursion (- x 1) (+ acc 1))))


(time
  (dotimes (x 100000)
    (foo 5)))

(time
  (dotimes (x 100000)
    (foo-tail-recursion 5 0)))

書き忘れましたが、末尾再帰は、

呼び出しを返した後で実行すべきことが残っていなければ、その呼び出しは、末尾呼び出しである。

だそうです。
なんか、On Lispにいっぱい出てきたキーワードなので、要注意ですね。


あと、timeマクロを使うと、

timeマクロは、式の評価に要した時間についてなんらかの指標(処理系による)を表示する

ということで、なんかあやふやな感じですが、どっちが速いかぐらいは分かりそうです。


で、結果はこう。

* 
FOO
* 
FOO-TAIL-RECURSION
* 
; Evaluation took:
;   1.46 seconds of real time
;   1.164072 seconds of user run time
;   0.140008 seconds of system run time
;   3,700,467,334 CPU cycles
;   [Run times include 0.05 seconds GC run time]
;   0 page faults and
;   57,600,256 bytes consed.
; 
NIL
* 
; Evaluation took:
;   1.7 seconds of real time
;   1.512095 seconds of user run time
;   0.184011 seconds of system run time
;   4,319,802,903 CPU cycles
;   [Run times include 0.1 seconds GC run time]
;   0 page faults and
;   79,200,448 bytes consed.
; 
NIL
*

というわけで、末尾再帰バージョンじゃない方が速かったりする。。
なんかそういうもんなの!?


あとの練習問題はパス。。