sicpm1.21〜m1.26?(3)
時間計測のところで時間を食った。
でも、そのおかげでループ処理が書けるようになった。
今日やったこと。
(define (smallest-divisor n) (find-divisor n 2)) (define (find-divisor n test-divisor) (cond ((> (square test-divisor) n) n) ((divides? test-divisor n) test-divisor) (else (find-divisor n (+ test-divisor 1))))) (define (divides? a b) (= (remainder b a) 0)) (define (square x) (* x x)) ;;m1.21 (smallest-divisor 199) ;=>199 (smallest-divisor 1999) ;=>1999 (smallest-divisor 19999) ;=>7 ;;素数か調べる↓ (define (prime? n) (= n (smallest-divisor n))) ;;条件式だけを書けば#t or #fの結果を出力できる ;;Fermat-test logN-search-prime ;(modn a)=(modn b) ;;nでわったときのあまりが等しい (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 (- n 1))))) (define (fast-prime? n times) (cond ((= times 0) true) ((fermat-test n) (fast-prime? n (- times 1))) (else false))) ;;runtime=システムが走った時間を示す整数を返す。 ;;runtimeの代わりにsys-timeを使った。 (define (timed-prime-test n) (newline) (display n) (start-prime-test n (sys-time))) (define (start-prime-test n start-time) (if (prime? n) (report-prime (- (sys-time) start-time)) '#f)) (define (report-prime elapsed-time) (display " *** ") (display elapsed-time) '#t) ;;displayで表示 (define (search-for-prime start-value counter) (cond ((= counter 0) "done") (else (if (timed-prime-test start-value) (search-for-prime (+ start-value 1) (- counter 1)) (search-for-prime (+ start-value 1) counter))))) ;;runtimeの()を外したら動いた。 ;;返す値を真偽値にする方法が分かった。 ;;m1.22は後で考える「unbound variable runtime]という表示がでます>< ;;ここ↓から、runtimeをもらってきました。 ;;http://www.csus4.net/hiki/SICPReading/?FujimotoHisaChapter1 ;; gauche用runtime (microsecを返す) ;;上手く動かない ;(define runtime ; (use srfi-11) ; (let-values (((a b) (sys-gettimeofday))) ; (+ (* a 1000000) b))) ;;*** ERROR: invalid application: (119044251300000) ;;続、m1.22 ;;一応できた。(時間が計測できないケド…) ;;1000-> 1009, 1013, 1019 ;;10000-> 10007, 10009, 10037 ;;100000-> 100003, 100019, 100043 ;;1000000-> 1000003, 1000033, 1000037 ;;以降の問題は計測不可能><(runtimeの代替案が見つかりません><) ;;m1.23 (define (smallest-divisor n) (find-divisor n 2)) (define (find-divisor n test-divisor) (cond ((> (square test-divisor) n) n) ((divides? test-divisor n) test-divisor) (else (find-divisor n (next test-divisor))))) (define (divides? a b) (= (remainder b a) 0)) (define (square x) (* x x)) (define (next test-divisor) (if (= test-divisor 2) 3 (+ test-divisor 2))) ;;後は素数の計算時間を調べる。2倍早くなることを期待。 ;;m1.24 timed-prime-test -> use fast-prime? ;;とりあえず、できそうな1.25と1.26からはじめてみる。 ;;m1.25 ;;よくわからなかった。問題としてでているから、正しくないのだと思うのだけれど… ;;(runtimeを探している時に見つけた回答によると、メモリ使用量が多くなるらしい) ;;桁数とかメモリ使用量とか把握するの苦手です>< ;;m1.26 ;たぶん、作用的順序だからだと思う。 ;試しに、fという関数が3回まで増えてから収束するようなときを考えてみる。 ;1,squareの場合 (square (f x)) (square (f (f x))) ;1 (square (f (fx))) ;;fx = (f x)で計算された値 (square (f (f (fx)))) ;1 (square (f (ffx))) (square (fffx)) ;1 ffffffx ;1 ;1+1+1+1=4 ;2,*を使った場合 (* (f x) (f x)) (* (f (f x)) (f ( f x))) ;2 (* (f fx) (f fx)) (* (f (f fx)) (f (f fx))) ;2 (* (f ffx) (f ffx)) ;2 (* fffx fffx) ;1 ffffffx ;2+2+2+1 ;;関数fがn回まで増えてから収束するとき、計算回数は1*n+1と2*n+1のように変わる。 ;;とりあえず*を使った方が効率が悪いということは分かった。 ;;m1.27,m1.28はめんどくさそう。 ;;1.3.1 (define (sum-integers a b) (if (> a b) 0 (+ a (sum-integers (+ a 1) b)))) (define (pi-sum a b) (if (> a b) 0 (+ (/ 1 (* a (+ a 2))) (pi-sum (+ a 4) b)))) (define (sum term a next b) (if (> a b) 0 (+ (term a) (sum term (next a) next b)))) ;;確かにみんなそうなっている。(sumでまとめられる!) (define (inc i) (+ i 1)) (define (cube x) (* x x x)) (define (sum-cubes a b) (sum cube a inc b)) ;;(sum-cubes 1 3) ;=> 36=1+8+27 (define (integral f a b dx) (define (add-dx x (+ x dx)) (* (sum f (+ a (/ dx 2.0)) add-dx b) dx)))
ステップ数、メモリ使用量などの計算のコツが掴めていないかもしれない。
(あとでまた考えると、分かるかもしれない)
復習?
newlineとdisplayの使い方を確かめるために、
今までの知識を使って作ってみた。
(define (fib n) (define (fib-iter a b n) (cond ((= n 0) b) (else (fib-iter (+ a b) a (- n 1))))) (fib-iter 1 0 n)) (define (fib-from-to from to result) (display result) (newline) (if (= from to) "done" (fib-from-to (+ from 1) to (fib from))))
gosh> (fib-from-to 1 10 0) 0 1 1 2 3 5 8 13 21 34 "done"
今のところはこんなところ。
追記
たぶん、こっちのほうがいい。
(define (fib-from-to from to) (define (fib-iter a b n) (cond ((>= (- to from) n) (display b) (newline))) (if (= n 0) "done" (fib-iter (+ a b) a (- n 1)))) (fib-iter 1 0 to))
gosh> (fib-from-to 8 10) 21 34 55 "done"
さらに追記
この方が計算量少ないかも( (- to from)を計算してないので)
(define (fib-from-to from to) (define (fib-iter a b n) (cond ((<= from n) (display b) (newline))) (if (= n to) "done" (fib-iter (+ a b) a (+ n 1)))) (fib-iter 1 0 0))
問題なのは、fib-iterの中にfib-from-to評価するべき式が入っているところ。
これでも、本質的にはおなじだし…
(define (fib-from-to from to) (define (output? n b) (cond ((<= from n) (display b) (newline)))) (define (fib-iter a b n) (output? n b) (if (= n to) "done" (fib-iter (+ a b) a (+ n 1)))) (fib-iter 1 0 0))