Chapter 1, Building Abstractions with Procedures
Section - Procedures and the Processes They Generate
Exercise 1.24
Present implementation of random
is not under sicp language. So I shall be importing it additionally.
Also, random
works only on numbers less than 4294967087
, so I created my-random
using random
. It is however more
costlier than random
as it internally calls random twice for numbers beyond integer range.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#lang sicp
(#%require (only racket/base random))
(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 (my-random (- n 1))))
)
(define MAX 10000000)
(define (my-random n)
(if (< n 4294967087)
(random n)
(+ (* (random (quotient n MAX)) MAX) (random (remainder n MAX)))
)
)
(define (fast-prime? n times)
(cond ((= times 0) true)
((fermat-test n) (fast-prime? n (- times 1)))
(else false)
)
)
(define (square x) (* x x))
(define (report-prime n elapsed-time)
(newline)
(display n)
(display " *** ")
(display elapsed-time)
1
)
(define (search-primes start count)
(define (search-primes-itr mm nn)
(if (> nn 0)
(if (> (elapsed-prime-time mm (runtime)) 0)
(search-primes-itr (+ mm 2) (dec nn))
(if (even? mm)
(search-primes-itr (+ mm 1) nn)
(search-primes-itr (+ mm 2) nn)
)
)
(newline)
)
)
(search-primes-itr start count)
)
(define (elapsed-prime-time n st)
(if (fast-prime? n 25)
(report-prime n (- (runtime) st))
0
)
)
Now I shall redraw the table from previous exercise including values from this exercise:
Numbers | Orignal approach with no skipping | Skipping even numbers by calling next-divisor | Skipping even numbers directly | fermat-prime? |
---|---|---|---|---|
1009 | 4 | 3 | 2 | 521 |
1013 | 4 | 3 | 2 | 541 |
1019 | 4 | 3 | 2 | 561 |
10007 | 12 | 9 | 7 | 661 |
10009 | 26 | 8 | 7 | 661 |
10037 | 13 | 7 | 5 | 671 |
100003 | 41 | 26 | 20 | 781 |
100019 | 40 | 27 | 19 | 801 |
100043 | 40 | 26 | 19 | 811 |
1000003 | 157 | 83 | 62 | 871 |
1000033 | 126 | 82 | 63 | 861 |
1000037 | 127 | 83 | 63 | 881 |
10000000000037 | 388727 | 279466 | 194440 | 6381 |
10000000000051 | 388108 | 279058 | 192753 | 6141 |
10000000000099 | 394797 | 304850 | 207065 | 6271 |
100000000000031 | 1238697 | 8375991 | 6426951 | 6971 |
100000000000067 | 1240527 | 8306311 | 6561041 | 7021 |
As we can see that exponential increments in input size causes only linear changes in processing-time using fermat-prime
.
Also we can note that for small numbers fermat-prime takes much more time because we are calling random function and trying multiple
times(25). But as input size increases, fermat-test
is much faster than the linear ones.