<< Previous exercise (1.21) | sicp-solutions | Next exercise (1.23) >>
;; ex 1.22 (define (square x) (* x x)) (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 (prime? n) (= n (smallest-divisor n))) (define (timed-prime-test n) (start-prime-test n (runtime))) (define (start-prime-test n start-time) (if (prime? n) (report-prime n (- (runtime) start-time)))) (define (report-prime n elapsed-time) (newline) (display n) (display " *** ") (display elapsed-time)) (define (search-for-primes lower upper) (define (iter n) (cond ((<= n upper) (timed-prime-test n) (iter (+ n 2))))) (iter (if (odd? lower) lower (+ lower 1)))) (search-for-primes 1000 1019) ; 1e3 (search-for-primes 10000 10037) ; 1e4 (search-for-primes 100000 100043) ; 1e5 (search-for-primes 1000000 1000037) ; 1e6 ; As of 2008, computers have become too fast to appreciate the time ; required to test the primality of such small numbers. ; To get meaningful results, we should perform the test with numbers ; greater by, say, a factor 1e6. (newline) (search-for-primes 1000000000 1000000021) ; 1e9 (search-for-primes 10000000000 10000000061) ; 1e10 (search-for-primes 100000000000 100000000057) ; 1e11 (search-for-primes 1000000000000 1000000000063) ; 1e12
The output produced by the above code is:
1009 *** 0. 1013 *** 0. 1019 *** 0. 10007 *** 0. 10009 *** 0. 10037 *** 0. 100003 *** 0. 100019 *** 0. 100043 *** 0. 1000003 *** 0. 1000033 *** 0. 1000037 *** 1.0000000000000002e-2 1000000007 *** .13 1000000009 *** .11999999999999997 1000000021 *** .10999999999999999 10000000019 *** .39 10000000033 *** .3799999999999999 10000000061 *** .3700000000000001 100000000003 *** 1.22 100000000019 *** 1.2300000000000004 100000000057 *** 1.2199999999999998 1000000000039 *** 3.829999999999999 1000000000061 *** 4.039999999999999 1000000000063 *** 3.9700000000000006
From our timing data, we can observe that, when increasing the tested number of a factor 10, the required time increases roughly of a factor 3. By noting that 3 ≅ √10, we can confirm both the growth prediction and the notion that programs run in a time proportional to the steps required for the computation.
Notes
(define (search-iter cur last)
(if (<= cur last)
(begin (timed-prime-test cur)
(search-iter (+ cur 2) last))))
Another implementation also easy to understand:
;basic operations (define (square x) (* x x)) (define (divides? a b) (= (remainder b a) 0)) (define (even? n) (= (remainder n 2) 0)) ;smallest divisor computation (define (smallest-divisor n) (define (find-divisor n test) (cond ((> (square test) n) n) ((divides? test n) test) (else (find-divisor n (+ test 1))))) (find-divisor n 2)) ;primality check (define (prime? n) (= n (smallest-divisor n))) ;check primality of consecutive odd integers in some range ;time&primality test ;drRacket has no (runtime) variable; had to substitute it with (current-milliseconds) which is basically same (define (runtime) (current-milliseconds)) (define (timed-prime-test n) (start-prime-test n (runtime))) (define (start-prime-test n start-time) (if (prime? n) (report-prime n (- (runtime) start-time)) #f)) (define (report-prime n elapsed-time) (display n) (display "***") (display elapsed-time) (newline)) ;search counter (define (search-for-primes n counter) (if (even? n) (s-f-p (+ n 1) counter) (s-f-p n counter))) ;it's important to pay attention to the fact that predicate of the first 'if' here calls (timed-prime-test n) which in case of #t computes into two procedures - (report-prime n (elapsed-time)) and 'then' case of the first 'if'. (define (s-f-p n counter) (if (> counter 0) (if (timed-prime-test n) (s-f-p (+ n 2) (- counter 1)) (s-f-p (+ n 2) counter)) "COMPUTATION COMPLETE"))
Output:
(search-for-primes 1000 3) 1009***0 1013***0 1019***0 "COMPUTATION COMPLETE" (search-for-primes 1000000 3) 1000003***0 1000033***0 1000037***0 "COMPUTATION COMPLETE" (search-for-primes 1000000000000 3) 1000000000039***359 1000000000061***359 1000000000063***406 "COMPUTATION COMPLETE"