Exercise 1.23
This is the 23rd exercise from Sicp.
The Question
Exercise 1.23: The smallest-divisor procedure shown at the
start of this section does lots of needless testing: After it checks to
see if the number is divisible by 2 there is no point in checking to
see if it is divisible by any larger even numbers. This suggests that
the values used for test-divisor
should not be 2, 3, 4, 5, 6, . . . ,
but rather 2, 3, 5, 7, 9, . . . . To implement this change, define a pro-
cedure next that returns 3 if its input is equal to 2 and otherwise
returns its input plus 2. Modify the smallest-divisor procedure
to use (next test-divisor) instead of (+ test-divisor 1) .
With timed-prime-test incorporating this modified version of
smallest-divisor , run the test for each of the 12 primes found
in Exercise 1.22. Since this modification halves the number of
test steps, you should expect it to run about twice as fast. Is this
expectation confirmed? If not, what is the observed ratio of the
speeds of the two algorithms, and how do you explain the fact that
it is different from 2?
My thoughts
The question is simple. Write a procedure next
that returns
3
if input
is 2 and input + 2
if odd. We then need to modify
find-divisor
to use this change.
After all that, we need to check if this makes any diffrence.
The Answer
This question is very simple. So I am not going to spend all my time explaining it.
next
This is the definition of next
:
(define (next input)
(if (= input 2)
3
(+ input 2)))
smallest-divisor
This is what smallest-divisor looks like:
(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))
What I have done is added a test checking if test-divisor
is even
and if it is also not equal to 2. If it is, use next
.
I also changed the increment value in find-divisor
to 2.
Checking if this makes any diffrence
Now, we check for a diffrence. Let’s use the code from the previous
exercise and modify smallest-divisor
and test-divisor
.
(define (next input)
(if (= input 2)
3
(+ input 2)))
(define (prime? n)
(= n (smallest-divisor n)))
(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 (timed-prime-test n)
(newline)
(display n)
(start-prime-test n (runtime)))
(define (start-prime-test n start-time)
(if (prime? n)
(report-prime (- (runtime) start-time))))
(define (report-prime elapsed-time)
(display " *** ")
(display elapsed-time))
(define (prime-range cur-val count req)
(cond ((not (= count req))
(if (prime? cur-val)
(and (timed-prime-test cur-val)
(prime-range (+ cur-val 2)(+ count 1) req))
(prime-range (+ cur-val 2) count req)))))
(define (search-for-primes range no-of-primes)
(prime-range (if (even? range)(- range 1) range) 0 no-of-primes))
Now, let’s test it :
(search-for-primes 100000000000 3)
100000000003 *** .15999999999999992
100000000019 *** .15999999999999992
100000000057 *** .1599999999999997
;Unspecified return value
Huge Diffrence ! What was 0.27 became 0.16 ! 0.27 divided by 0.16 is 1.6875. While, this is not 2, It is 1.7
Answering Sicp’s Questions
No, the expectation is not confirmed. The observed ratio 0.25:0.16. This can be written as 25:16
How do I explain this ?
I think this .04 difference can be attributed to next
. We have a lot
more tests and evaluations happening because of, it. However, in my
opinion being 1.6 times faster is a big thing.