問題1.22

さあ面白くなってきた。

素数を求めるのに必要な時間を調べ、考察せよ

C言語なら単純なforループになるコードだが、Lispだと末尾再帰を使って解く必要がある。
残念ながら自力で書くことは出来なかっので、AnswerBookをコピーしてコード読み。

(define (search-for-primes from n)
  (cond ((= n 0) (newline) 'done)
        ((even? from) (search-for-primes (+ from 1) n))
        ((timed-prime-test from) (search-for-primes (+ from 2) (- n 1)))
        (else (search-for-primes (+ from 2) n))))

(define (timed-prime-test n)
  (newline)
  (display n)
  (start-prime-test n (get-internal-real-time)))

(define (start-prime-test n start-time)
  (if (prime-loop n 500)
      (report-prime (- (get-internal-real-time) start-time))))

(define (prime-loop n try-num)
  (define (iter i)
    (cond ((= i 0) 'done)
	  ((prime? n) (iter (- i 1)))
	  (else (iter (- i 1)))))
  (iter try-num)
  (prime? n))

(define (report-prime elapsed-time)
  (display " *** ")
  (display elapsed-time))

なるほど、

  (cond ((= n 0) (newline) 'done)

のように書くと、

guile> (search-for-primes 100 30)
.
.
159
done

対話モードの最後に'done'が出力されるのか。

所で

(define (search-for-primes from n)
  (cond ((= n 0) (newline) 'done)
        ((even? from) (search-for-primes (+ from 1) n))
        ((timed-prime-test from) (search-for-primes (+ from 2) (- n 1)))
        (else (search-for-primes (+ from 2) n))))

の、timed-prime-testは何が返り値として返ってくるんだろ?
素数の場合も、そうじゃない場合も最後に実行されるのはdisplay関数のはず。

  • とりあえず、自分のマシンだと素数計算が早くて時間が正確に計測できなかったので、prime-loopで複数回(自分の環境では501回)繰り返す事にした。AnswerBookでは、time-differenceという関数を使ってさらに正確に測っている。
  • guileにruntimeという関数は無かったのでget-internal-real-timeという関数を使っている。ドキュメントが少なくて、こういう関数があるということを調べるのが大変だった...。


とりあえず実行結果は以下。
長くなってきたので詳しい解析は次の記事で。

guile> (search-for-primes 1000 30)

1001
1003
1005
1007
1009 *** 62
1011
1013 *** 63
1015
1017
1019 *** 62
1021 *** 63
1023
1025
1027
1029
1031 *** 63
1033 *** 47
1035
1037
1039 *** 62
1041
1043
1045
1047
1049 *** 46
1051 *** 63
1053
1055
1057
1059
done