From 8571154996adbd40544f4746f812af3e34fa38c8 Mon Sep 17 00:00:00 2001 From: Correl Roush Date: Mon, 19 May 2014 02:08:41 -0400 Subject: [PATCH] Section 1.2 --- 1-2.org | 494 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1-2.scm | 429 ------------------------------------------------ 2 files changed, 494 insertions(+), 429 deletions(-) create mode 100644 1-2.org delete mode 100644 1-2.scm diff --git a/1-2.org b/1-2.org new file mode 100644 index 0000000..3682849 --- /dev/null +++ b/1-2.org @@ -0,0 +1,494 @@ +#+BEGIN_HTML +--- +title: 1.2 - Procedures and the Processes They Generate +layout: org +--- +#+END_HTML + +* Linear Recursion and Iteration + + #+BEGIN_SRC scheme :tangle yes + ;; =================================================================== + ;; 1.2.1: Linear Recursion and Iteration + ;; =================================================================== + + (define (inc n) (+ n 1)) + (define (dec n) (- n 1)) + #+END_SRC + +** Exercise 1.9 + Each of the following two procedures defines a + method for adding two positive integers in terms of the procedures + `inc', which increments its argument by 1, and `dec', which + decrements its argument by 1. + + #+BEGIN_SRC scheme + (define (+ a b) + (if (= a 0) + b + (inc (+ (dec a) b)))) + + (define (+ a b) + (if (= a 0) + b + (+ (dec a) (inc b)))) + #+END_SRC + + Using the substitution model, illustrate the process generated by + each procedure in evaluating `(+ 4 5)'. Are these processes + iterative or recursive? + + -------------------------------------------------------------------- + + #+BEGIN_SRC scheme :tangle yes + ;; ------------------------------------------------------------------- + ;; Exercise 1.9 + ;; ------------------------------------------------------------------- + + ;; First procedure: Recursive + (+ 4 5) + (inc (+ 3 5)) + (inc (inc (+ 2 5))) + (inc (inc (inc (+ 1 5)))) + (inc (inc (inc (inc (+ 0 5))))) + (inc (inc (inc (inc 5)))) + (inc (inc (inc 6))) + (inc (inc 7)) + (inc 8) + 9 + + ;; Second procedure: Iterative + (+ 4 5) + (+ 3 6) + (+ 2 7) + (+ 1 8) + (+ 0 9) + 9 + #+END_SRC + +** Exercise 1.10 + The following procedure computes a mathematical + function called Ackermann's function. + + #+BEGIN_SRC scheme + (define (A x y) + (cond ((= y 0) 0) + ((= x 0) (* 2 y)) + ((= y 1) 2) + (else (A (- x 1) + (A x (- y 1)))))) + + #+END_SRC + + What are the values of the following expressions? + + #+BEGIN_SRC scheme + (A 1 10) + 24 + + (A 2 4) + 536 + + (A 3 3) + 536 + #+END_SRC + + Consider the following procedures, where `A' is the procedure + defined above: + + #+BEGIN_SRC scheme + (define (f n) (A 0 n)) + + (define (g n) (A 1 n)) + + (define (h n) (A 2 n)) + + (define (k n) (* 5 n n)) + + #+END_SRC + + Give concise mathematical definitions for the functions computed + by the procedures `f', `g', and `h' for positive integer values of + n. For example, `(k n)' computes 5n^2. + -------------------------------------------------------------------- + + `(f n)' computes 2n + `(g n)' computes ... + +* 1.2.2: Tree Recursion + + #+BEGIN_SRC scheme :tangle yes + ;; =================================================================== + ;; 1.2.2: Tree Recursion + ;; =================================================================== + + (define (fib n) + (fib-iter 1 0 n)) + + (define (fib-iter a b count) + (if (= count 0) + b + (fib-iter (+ a b) a (- count 1)))) + #+END_SRC + +** Exercise 1.11 + A function f is defined by the rule that f(n) = n + if n<3 and f(n) = f(n - 1) + 2f(n - 2) + 3f(n - 3) if n>= 3. + Write a procedure that computes f by means of a recursive process. + Write a procedure that computes f by means of an iterative + process. + + -------------------------------------------------------------------- + + #+BEGIN_SRC scheme :tangle yes + ;; ------------------------------------------------------------------- + ;; Exercise 1.11 + ;; ------------------------------------------------------------------- + + (define (f-recursive n) + (if (< n 3) + n + (+ (f-recursive (- n 1)) + (* 2 (f-recursive (- n 2))) + (* 3 (f-recursive (- n 3)))))) + + (define (f-iterative n) + (define (do-iter a b c n) + (if (< n 3) + a + (do-iter (+ a (* 2 b) (* 3 c)) a b (- n 1)))) + (if (< n 3) + n + (do-iter 2 1 0 n))) + #+END_SRC + +** Exercise 1.12 + The following pattern of numbers is called "Pascal's + triangle". + + #+BEGIN_EXAMPLE + 1 + 1 1 + 1 2 1 + 1 3 3 1 + 1 4 6 4 1 + #+END_EXAMPLE + + The numbers at the edge of the triangle are all 1, and each number + inside the triangle is the sum of the two numbers above it.(4) + Write a procedure that computes elements of Pascal's triangle by + means of a recursive process. + + -------------------------------------------------------------------- + + #+BEGIN_SRC scheme :tangle yes + ;; ------------------------------------------------------------------- + ;; Exercise 1.12 + ;; ------------------------------------------------------------------- + + (define (pascal row column) + (cond ((= column 1) 1) + ((= row column) 1) + (#t (+ (pascal (- row 1) (- column 1)) + (pascal (- row 1) column))))) + #+END_SRC + +** Exercise 1.13 + Prove that _Fib_(n) is the closest integer to + [phi]^n/[sqrt](5), where [phi] = (1 + [sqrt](5))/2. Hint: Let + [illegiblesymbol] = (1 - [sqrt](5))/2. Use induction and the + definition of the Fibonacci numbers (see section *Note 1-2-2::) to + prove that _Fib_(n) = ([phi]^n - [illegiblesymbol]^n)/[sqrt](5). + + -------------------------------------------------------------------- + + http://www.billthelizard.com/2009/12/sicp-exercise-113-fibonacci-and-golden.html + +* 1.2.3: Orders of Growth + +** Exercise 1.14 + Draw the tree illustrating the process generated + by the `count-change' procedure of section *Note 1-2-2:: in making + change for 11 cents. What are the orders of growth of the space + and number of steps used by this process as the amount to be + changed increases? + +** Exercise 1.15 + The sine of an angle (specified in radians) can + be computed by making use of the approximation `sin' xapprox x if + x is sufficiently small, and the trigonometric identity + + #+BEGIN_EXAMPLE + x x + sin x = 3 sin --- - 4 sin^3 --- + 3 3 + #+END_EXAMPLE + + to reduce the size of the argument of `sin'. (For purposes of this + exercise an angle is considered "sufficiently small" if its + magnitude is not greater than 0.1 radians.) These ideas are + incorporated in the following procedures: + + #+BEGIN_SRC scheme + (define (cube x) (* x x x)) + + (define (p x) (- (* 3 x) (* 4 (cube x)))) + + (define (sine angle) + (if (not (> (abs angle) 0.1)) + angle + (p (sine (/ angle 3.0))))) + #+END_SRC + + a. How many times is the procedure `p' applied when `(sine + 12.15)' is evaluated? + + b. What is the order of growth in space and number of steps (as + a function of a) used by the process generated by the `sine' + procedure when `(sine a)' is evaluated? + +* 1.2.4: Exponentiation + +** Exercise 1.16 + Design a procedure that evolves an iterative + exponentiation process that uses successive squaring and uses a + logarithmic number of steps, as does `fast-expt'. (Hint: Using the + observation that (b^(n/2))^2 = (b^2)^(n/2), keep, along with the + exponent n and the base b, an additional state variable a, and + define the state transformation in such a way that the product a + b^n is unchanged from state to state. At the beginning of the + process a is taken to be 1, and the answer is given by the value + of a at the end of the process. In general, the technique of + defining an "invariant quantity" that remains unchanged from state + to state is a powerful way to think about the design of iterative + algorithms.) + +** Exercise 1.17 + The exponentiation algorithms in this section are + based on performing exponentiation by means of repeated + multiplication. In a similar way, one can perform integer + multiplication by means of repeated addition. The following + multiplication procedure (in which it is assumed that our language + can only add, not multiply) is analogous to the `expt' procedure: + + #+BEGIN_SRC scheme + (define (* a b) + (if (= b 0) + 0 + (+ a (* a (- b 1))))) + #+END_SRC + + This algorithm takes a number of steps that is linear in `b'. Now + suppose we include, together with addition, operations `double', + which doubles an integer, and `halve', which divides an (even) + integer by 2. Using these, design a multiplication procedure + analogous to `fast-expt' that uses a logarithmic number of steps. + +** Exercise 1.18 + Using the results of *Note Exercise 1-16:: and + *Note Exercise 1-17::, devise a procedure that generates an + iterative process for multiplying two integers in terms of adding, + doubling, and halving and uses a logarithmic number of steps.(4) + +** Exercise 1.19 + There is a clever algorithm for computing the + Fibonacci numbers in a logarithmic number of steps. Recall the + transformation of the state variables a and b in the `fib-iter' + process of section *Note 1-2-2::: a <- a + b and b <- a. Call + this transformation T, and observe that applying T over and over + again n times, starting with 1 and 0, produces the pair _Fib_(n + + 1) and _Fib_(n). In other words, the Fibonacci numbers are + produced by applying T^n, the nth power of the transformation T, + starting with the pair (1,0). Now consider T to be the special + case of p = 0 and q = 1 in a family of transformations T_(pq), + where T_(pq) transforms the pair (a,b) according to a <- bq + aq + + ap and b <- bp + aq. Show that if we apply such a transformation + T_(pq) twice, the effect is the same as using a single + transformation T_(p'q') of the same form, and compute p' and q' in + terms of p and q. This gives us an explicit way to square these + transformations, and thus we can compute T^n using successive + squaring, as in the `fast-expt' procedure. Put this all together + to complete the following procedure, which runs in a logarithmic + number of steps:(5) + + #+BEGIN_SRC scheme + ;; ------------------------------------------------------------------- + ;; Exercise 1.19 + ;; ------------------------------------------------------------------- + + (define (fib n) + (fib-iter 1 0 0 1 n)) + + (define (fib-iter a b p q count) + (cond ((= count 0) b) + ((even? count) + (fib-iter a + b + ; compute p' + ; compute q' + (/ count 2))) + (else (fib-iter (+ (* b q) (* a q) (* a p)) + (+ (* b p) (* a q)) + p + q + (- count 1))))) + #+END_SRC + +* 1.2.5: Greatest Common Divisors + +** Exercise 1.20 + The process that a procedure generates is of + course dependent on the rules used by the interpreter. As an + example, consider the iterative `gcd' procedure given above. + Suppose we were to interpret this procedure using normal-order + evaluation, as discussed in section *Note 1-1-5::. (The + normal-order-evaluation rule for `if' is described in *Note + Exercise 1-5::.) Using the substitution method (for normal + order), illustrate the process generated in evaluating `(gcd 206 + 40)' and indicate the `remainder' operations that are actually + performed. How many `remainder' operations are actually performed + in the normal-order evaluation of `(gcd 206 40)'? In the + applicative-order evaluation? + +* 1.2.6: Example: Testing for Primality + +** Exercise 1.21 + Use the `smallest-divisor' procedure to find the + smallest divisor of each of the following numbers: 199, 1999, + 19999. + +** Exercise 1.22 + Most Lisp implementations include a primitive + called `runtime' that returns an integer that specifies the amount + of time the system has been running (measured, for example, in + microseconds). The following `timed-prime-test' procedure, when + called with an integer n, prints n and checks to see if n is + prime. If n is prime, the procedure prints three asterisks + followed by the amount of time used in performing the test. + + #+BEGIN_SRC scheme + (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)) + #+END_SRC + + Using this procedure, write a procedure `search-for-primes' that + checks the primality of consecutive odd integers in a specified + range. Use your procedure to find the three smallest primes + larger than 1000; larger than 10,000; larger than 100,000; larger + than 1,000,000. Note the time needed to test each prime. Since + the testing algorithm has order of growth of [theta](_[sqrt]_(n)), + you should expect that testing for primes around 10,000 should + take about _[sqrt]_(10) times as long as testing for primes around + 1000. Do your timing data bear this out? How well do the data + for 100,000 and 1,000,000 support the _[sqrt]_(n) prediction? Is + your result compatible with the notion that programs on your + machine run in time proportional to the number of steps required + for the computation? + +** 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 procedure `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 + *Note 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? + +** Exercise 1.24 + Modify the `timed-prime-test' procedure of *Note + Exercise 1-22:: to use `fast-prime?' (the Fermat method), and test + each of the 12 primes you found in that exercise. Since the + Fermat test has [theta](`log' n) growth, how would you expect the + time to test primes near 1,000,000 to compare with the time needed + to test primes near 1000? Do your data bear this out? Can you + explain any discrepancy you find? + +** Exercise 1.25 + Alyssa P. Hacker complains that we went to a lot + of extra work in writing `expmod'. After all, she says, since we + already know how to compute exponentials, we could have simply + written + + #+BEGIN_SRC scheme + (define (expmod base exp m) + (remainder (fast-expt base exp) m)) + #+END_SRC + + Is she correct? Would this procedure serve as well for our fast + prime tester? Explain. + +** Exercise 1.26 + Louis Reasoner is having great difficulty doing + *Note Exercise 1-24::. His `fast-prime?' test seems to run more + slowly than his `prime?' test. Louis calls his friend Eva Lu Ator + over to help. When they examine Louis's code, they find that he + has rewritten the `expmod' procedure to use an explicit + multiplication, rather than calling `square': + + #+BEGIN_SRC scheme + (define (expmod base exp m) + (cond ((= exp 0) 1) + ((even? exp) + (remainder (* (expmod base (/ exp 2) m) + (expmod base (/ exp 2) m)) + m)) + (else + (remainder (* base (expmod base (- exp 1) m)) + m)))) + #+END_SRC + + "I don't see what difference that could make," says Louis. "I + do." says Eva. "By writing the procedure like that, you have + transformed the [theta](`log' n) process into a [theta](n) + process." Explain. + +** Exercise 1.27 + Demonstrate that the Carmichael numbers listed in + *Note Footnote 1-47:: really do fool the Fermat test. That is, + write a procedure that takes an integer n and tests whether a^n is + congruent to a modulo n for every a= 3. -;; Write a procedure that computes f by means of a recursive process. -;; Write a procedure that computes f by means of an iterative -;; process. -;; -------------------------------------------------------------------- - -(define (f-recursive n) - (if (< n 3) - n - (+ (f-recursive (- n 1)) - (* 2 (f-recursive (- n 2))) - (* 3 (f-recursive (- n 3)))))) - -(define (f-iterative n) - (define (do-iter a b c n) - (if (< n 3) - a - (do-iter (+ a (* 2 b) (* 3 c)) a b (- n 1)))) - (if (< n 3) - n - (do-iter 2 1 0 n))) - -;; ==================================================================== -;; *Exercise 1.12:* The following pattern of numbers is called "Pascal's -;; triangle". -;; -;; 1 -;; 1 1 -;; 1 2 1 -;; 1 3 3 1 -;; 1 4 6 4 1 -;; -;; The numbers at the edge of the triangle are all 1, and each number -;; inside the triangle is the sum of the two numbers above it.(4) -;; Write a procedure that computes elements of Pascal's triangle by -;; means of a recursive process. -;; -------------------------------------------------------------------- - -(define (pascal row column) - (cond ((= column 1) 1) - ((= row column) 1) - (#t (+ (pascal (- row 1) (- column 1)) - (pascal (- row 1) column))))) - -;; ==================================================================== -;; *Exercise 1.13:* Prove that _Fib_(n) is the closest integer to -;; [phi]^n/[sqrt](5), where [phi] = (1 + [sqrt](5))/2. Hint: Let -;; [illegiblesymbol] = (1 - [sqrt](5))/2. Use induction and the -;; definition of the Fibonacci numbers (see section *Note 1-2-2::) to -;; prove that _Fib_(n) = ([phi]^n - [illegiblesymbol]^n)/[sqrt](5). -;; -------------------------------------------------------------------- - -;; http://www.billthelizard.com/2009/12/sicp-exercise-113-fibonacci-and-golden.html - -;; ==================================================================== -;; 1.2.3: Orders of Growth -;; ==================================================================== - -;; *Exercise 1.14:* Draw the tree illustrating the process generated -;; by the `count-change' procedure of section *Note 1-2-2:: in making -;; change for 11 cents. What are the orders of growth of the space -;; and number of steps used by this process as the amount to be -;; changed increases? -;; -;; *Exercise 1.15:* The sine of an angle (specified in radians) can -;; be computed by making use of the approximation `sin' xapprox x if -;; x is sufficiently small, and the trigonometric identity -;; -;; x x -;; sin x = 3 sin --- - 4 sin^3 --- -;; 3 3 -;; -;; to reduce the size of the argument of `sin'. (For purposes of this -;; exercise an angle is considered "sufficiently small" if its -;; magnitude is not greater than 0.1 radians.) These ideas are -;; incorporated in the following procedures: -;; -;; (define (cube x) (* x x x)) -;; -;; (define (p x) (- (* 3 x) (* 4 (cube x)))) -;; -;; (define (sine angle) -;; (if (not (> (abs angle) 0.1)) -;; angle -;; (p (sine (/ angle 3.0))))) -;; -;; a. How many times is the procedure `p' applied when `(sine -;; 12.15)' is evaluated? -;; -;; b. What is the order of growth in space and number of steps (as -;; a function of a) used by the process generated by the `sine' -;; procedure when `(sine a)' is evaluated? - -;; ==================================================================== -;; 1.2.4: Exponentiation -;; -------------------------------------------------------------------- - -;; *Exercise 1.16:* Design a procedure that evolves an iterative -;; exponentiation process that uses successive squaring and uses a -;; logarithmic number of steps, as does `fast-expt'. (Hint: Using the -;; observation that (b^(n/2))^2 = (b^2)^(n/2), keep, along with the -;; exponent n and the base b, an additional state variable a, and -;; define the state transformation in such a way that the product a -;; b^n is unchanged from state to state. At the beginning of the -;; process a is taken to be 1, and the answer is given by the value -;; of a at the end of the process. In general, the technique of -;; defining an "invariant quantity" that remains unchanged from state -;; to state is a powerful way to think about the design of iterative -;; algorithms.) -;; -;; *Exercise 1.17:* The exponentiation algorithms in this section are -;; based on performing exponentiation by means of repeated -;; multiplication. In a similar way, one can perform integer -;; multiplication by means of repeated addition. The following -;; multiplication procedure (in which it is assumed that our language -;; can only add, not multiply) is analogous to the `expt' procedure: -;; -;; (define (* a b) -;; (if (= b 0) -;; 0 -;; (+ a (* a (- b 1))))) -;; -;; This algorithm takes a number of steps that is linear in `b'. Now -;; suppose we include, together with addition, operations `double', -;; which doubles an integer, and `halve', which divides an (even) -;; integer by 2. Using these, design a multiplication procedure -;; analogous to `fast-expt' that uses a logarithmic number of steps. -;; -;; *Exercise 1.18:* Using the results of *Note Exercise 1-16:: and -;; *Note Exercise 1-17::, devise a procedure that generates an -;; iterative process for multiplying two integers in terms of adding, -;; doubling, and halving and uses a logarithmic number of steps.(4) -;; -;; *Exercise 1.19:* There is a clever algorithm for computing the -;; Fibonacci numbers in a logarithmic number of steps. Recall the -;; transformation of the state variables a and b in the `fib-iter' -;; process of section *Note 1-2-2::: a <- a + b and b <- a. Call -;; this transformation T, and observe that applying T over and over -;; again n times, starting with 1 and 0, produces the pair _Fib_(n + -;; 1) and _Fib_(n). In other words, the Fibonacci numbers are -;; produced by applying T^n, the nth power of the transformation T, -;; starting with the pair (1,0). Now consider T to be the special -;; case of p = 0 and q = 1 in a family of transformations T_(pq), -;; where T_(pq) transforms the pair (a,b) according to a <- bq + aq + -;; ap and b <- bp + aq. Show that if we apply such a transformation -;; T_(pq) twice, the effect is the same as using a single -;; transformation T_(p'q') of the same form, and compute p' and q' in -;; terms of p and q. This gives us an explicit way to square these -;; transformations, and thus we can compute T^n using successive -;; squaring, as in the `fast-expt' procedure. Put this all together -;; to complete the following procedure, which runs in a logarithmic -;; number of steps:(5) -;; -;; (define (fib n) -;; (fib-iter 1 0 0 1 n)) -;; -;; (define (fib-iter a b p q count) -;; (cond ((= count 0) b) -;; ((even? count) -;; (fib-iter a -;; b -;; ; compute p' -;; ; compute q' -;; (/ count 2))) -;; (else (fib-iter (+ (* b q) (* a q) (* a p)) -;; (+ (* b p) (* a q)) -;; p -;; q -;; (- count 1))))) - -;; ==================================================================== -;; 1.2.5: Greatest Common Divisors -;; ==================================================================== - -;; *Exercise 1.20:* The process that a procedure generates is of -;; course dependent on the rules used by the interpreter. As an -;; example, consider the iterative `gcd' procedure given above. -;; Suppose we were to interpret this procedure using normal-order -;; evaluation, as discussed in section *Note 1-1-5::. (The -;; normal-order-evaluation rule for `if' is described in *Note -;; Exercise 1-5::.) Using the substitution method (for normal -;; order), illustrate the process generated in evaluating `(gcd 206 -;; 40)' and indicate the `remainder' operations that are actually -;; performed. How many `remainder' operations are actually performed -;; in the normal-order evaluation of `(gcd 206 40)'? In the -;; applicative-order evaluation? - -;; ==================================================================== -;; 1.2.6: Example: Testing for Primality -;; ==================================================================== - -;; *Exercise 1.21:* Use the `smallest-divisor' procedure to find the -;; smallest divisor of each of the following numbers: 199, 1999, -;; 19999. -;; -;; *Exercise 1.22:* Most Lisp implementations include a primitive -;; called `runtime' that returns an integer that specifies the amount -;; of time the system has been running (measured, for example, in -;; microseconds). The following `timed-prime-test' procedure, when -;; called with an integer n, prints n and checks to see if n is -;; prime. If n is prime, the procedure prints three asterisks -;; followed by the amount of time used in performing the test. -;; -;; (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)) -;; -;; Using this procedure, write a procedure `search-for-primes' that -;; checks the primality of consecutive odd integers in a specified -;; range. Use your procedure to find the three smallest primes -;; larger than 1000; larger than 10,000; larger than 100,000; larger -;; than 1,000,000. Note the time needed to test each prime. Since -;; the testing algorithm has order of growth of [theta](_[sqrt]_(n)), -;; you should expect that testing for primes around 10,000 should -;; take about _[sqrt]_(10) times as long as testing for primes around -;; 1000. Do your timing data bear this out? How well do the data -;; for 100,000 and 1,000,000 support the _[sqrt]_(n) prediction? Is -;; your result compatible with the notion that programs on your -;; machine run in time proportional to the number of steps required -;; for the computation? -;; -;; *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 procedure `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 -;; *Note 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? -;; -;; *Exercise 1.24:* Modify the `timed-prime-test' procedure of *Note -;; Exercise 1-22:: to use `fast-prime?' (the Fermat method), and test -;; each of the 12 primes you found in that exercise. Since the -;; Fermat test has [theta](`log' n) growth, how would you expect the -;; time to test primes near 1,000,000 to compare with the time needed -;; to test primes near 1000? Do your data bear this out? Can you -;; explain any discrepancy you find? -;; -;; *Exercise 1.25:* Alyssa P. Hacker complains that we went to a lot -;; of extra work in writing `expmod'. After all, she says, since we -;; already know how to compute exponentials, we could have simply -;; written -;; -;; (define (expmod base exp m) -;; (remainder (fast-expt base exp) m)) -;; -;; Is she correct? Would this procedure serve as well for our fast -;; prime tester? Explain. -;; -;; *Exercise 1.26:* Louis Reasoner is having great difficulty doing -;; *Note Exercise 1-24::. His `fast-prime?' test seems to run more -;; slowly than his `prime?' test. Louis calls his friend Eva Lu Ator -;; over to help. When they examine Louis's code, they find that he -;; has rewritten the `expmod' procedure to use an explicit -;; multiplication, rather than calling `square': -;; -;; (define (expmod base exp m) -;; (cond ((= exp 0) 1) -;; ((even? exp) -;; (remainder (* (expmod base (/ exp 2) m) -;; (expmod base (/ exp 2) m)) -;; m)) -;; (else -;; (remainder (* base (expmod base (- exp 1) m)) -;; m)))) -;; -;; "I don't see what difference that could make," says Louis. "I -;; do." says Eva. "By writing the procedure like that, you have -;; transformed the [theta](`log' n) process into a [theta](n) -;; process." Explain. -;; -;; *Exercise 1.27:* Demonstrate that the Carmichael numbers listed in -;; *Note Footnote 1-47:: really do fool the Fermat test. That is, -;; write a procedure that takes an integer n and tests whether a^n is -;; congruent to a modulo n for every a