開発環境
- OS X Mavericks - Apple(OS)
- Emacs (CUI)、BBEdit - Bare Bones Software, Inc. (GUI) (Text Editor)
- Scheme (プログラミング言語)
- Gauche (処理系)
計算機プログラムの構造と解釈(Gerald Jay Sussman(原著)、Julie Sussman(原著)、Harold Abelson(原著)、和田 英一(翻訳)、ピアソンエデュケーション、原書: Structure and Interpretation of Computer Programs (MIT Electrical Engineering and Computer Science)(SICP))の1(手続きによる抽象の構築)、1.2(手続きとその生成するプロセス)、1.2.6(例: 素数性のテスト)、問題 1.24.を解いてみる。
その他参考書籍
- Instructor's Manual to Accompany Structure & Interpretation of Computer Programs
- プログラミングGauche (Kahuaプロジェクト (著), 川合 史朗 (監修), オライリージャパン)
問題 1.24.
コード(BBEdit, Emacs)
sample.scm
#!/usr/bin/env gosh ;; -*- coding: utf-8 -*- (use srfi-11) ;; runtime手続きで使うsys-gettimeofday手続きのため必要 (use srfi-27) ;; fermat-test手続きで使うrandom-integer手続きのため必要 (define (expmod base exp m) (cond ((= exp 0) 1) ((even? exp) (remainder (square (expmod base (/ exp 2) m)) m)) (else (remainder (* base (expmod base (- exp 1) m)) m)))) (define (fermat-test n) (define (try-it a) (= (expmod a n n) a)) (try-it (+ 1 (random-integer (- n 1))))) (define (fast-prime? n times) (cond ((= times 0) true) ((fermat-test n) (fast-prime? n (- times 1))) (else false))) ;; Fermatテスト回数を1000回とする (define (start-prime-test n start-time) (if (fast-prime? n 1000) (report-prime (- (runtime) start-time)))) ;; (define true #t) (define false #f) (define (square x) (* x x)) (define (runtime) (let-values (((a b) (sys-gettimeofday))) (+ (* 1000000 a) b))) (define (timed-prime-test n) (newline) (display n) (start-prime-test n (runtime))) (define (report-prime elapsed-time) (display " *** ") (display elapsed-time)) (define primes '(10000000019 10000000033 10000000061 100000000003 100000000019 100000000057 1000000000039 1000000000061 1000000000063 10000000000037 10000000000051 10000000000099 100000000000031 100000000000067 100000000000097)) (for-each timed-prime-test primes)
入出力結果(Terminal, REPL(Read, Eval, Print, Loop))
$ gosh> (load "./sample") 10000000019 *** 64107 10000000033 *** 68823 10000000061 *** 90062 100000000003 *** 131312 100000000019 *** 87337 100000000057 *** 97408 1000000000039 *** 145733 1000000000061 *** 90992 1000000000063 *** 91824 10000000000037 *** 174043 10000000000051 *** 96148 10000000000099 *** 95866 100000000000031 *** 172429 100000000000067 *** 107017 100000000000097 *** 128780#t gosh> (/ (log 100000000000000) (log 10000000000)) 1.4000000000000001 gosh> (/ (+ 172429 107017 128780) (+ 64107 68823 90062.0)) 1.8306755399296837 gosh> (exit) $
FermatテストはΦ(log n)の増加なので、それのみを考慮すると、100000000000000(10^14)近くの素数をテストする時間は10000000000(10^10)近くの素数をテストする時間の約1.4倍になると予想される。実際は、Fermatテストを置くなう十分な回数を1000回とした場合、約1.8倍となっている。この違いは、Fermatテストの手続きで、手続き+、手続きrandom-integer、手続き-を適用するという事情で、その分予想より遅くなったと考えられる。
0 コメント:
コメントを投稿