なんだこれは

はてなダイアリーから移転しました。

ccl で 1からNまで足してみた

exercism.io というプログラムの学習サイトで課題をこなしている。
そこであったlispの課題で、1からNまで足して二乗するという計算があった。
もちろん、数学の公式をつかえばいいのはわかっているんだけれども、これ以外の方法で試してみた。

(defun square (x)
  (* x x))

(defun square-of-sums (x)
  (square (/ (* x (1+ x)) 2)))

実行結果

とりあえず、CPSスタイルは処理時間がかかるのでお勧めしません。

n=1000 での比較 (total,user systemはミリ秒)
method total user system memory
normal 4 5 5 0
recursive 35 36 8 0
loop 19 20 3 0
cps 637 505 134 800000
apply + 216 170 48 160000
reduce 556 438 62 160000
n=1000000での比較 (total,user systemはミリ秒)
method total user system memory
normal 5 6 5 32
recursive 2114 2109 6 32
loop 2312 2286 37 32
cps 371697 294948 22582 80000032
apply + - - - -
reduce 103234 96548 6235 16000032

apply + は "Too many argument"というエラーが発生して実行できなかった

実装

(defun square-of-sums-loop (x)
  (square
   (loop for n upto x sum n)))

(defun square-of-sums-recursive (x)
  (labels
      ((sum (n acc)
	 (if (<= n 0)
	     acc
	     (sum (1- n) (+ acc n)))))
    (square (sum x 0))))

(defun square-of-sums-cps (x)
  (labels
      ((sum (n cont)
	 (if (<= n 0)
	     (funcall cont 0)
	     (sum (1- n) #'(lambda (x) (funcall cont (+ n x)))))))
    (square (sum x #'identity))))

(defun square-of-sums-+ (x)
  (square 
   (apply #'+ (iota x))))

(defun square-of-sums-reduce (x)
  (square
   (reduce #'+ (iota x))))

(defun iota (end &optional (start 0) (acc nil))
  (if (zerop end)
      (nreverse acc)
      (iota (1- end) (1+ start) (cons start acc))))