1.16
(define (fast-expt b n) (fast-expt-iter b n 1)) (define (fast-expt-iter b n a) (cond ((= n 0) a) ((even? n) (fast-expt-iter (* b b) (/ n 2) a)) (else (fast-expt-iter b (- n 1) (* b a)))))
1.17
这道题中,我把参数名字改了一下,使得它和1.16题中的名称保持一致,其思路完全类似于乘幂的运算。
(define (fast-* b n) (cond ((= n 0) 0) ((even? n) (double (fast-* b (halve n)))) (else (+ b (fast-* b (- n 1)))))) (define (double x) (+ x x)) (define (halve x) (/ x 2))
1.18
(define (double x) (+ x x)) (define (halve x) (/ x 2)) (define (fast-* b n) (fast-*-iter b n 0)) (define (fast-*-iter b n a) (cond ((= n 0) a) ((even? n) (fast-*-iter (double b) (halve n) a)) (else (fast-*-iter b (- n 1) (+ a b)))))
1.19
对(a,b)经行两次Tpq变换的过程如下:
(a, b)---->(bq+aq+ap, bq+aq)---->(b(q^2 + 2pq) + a(q^2 + 2pq) + a(q^2 + p^2), b(q^2+p^2) + a(q^2 + 2pq))
所以,q'= q^2+2pq,p'= (q^2 + p^2)。
(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 (+ (square p) (square q)) (+ (square q) (* 2 p q)) (/ count 2))) (else (fib-iter (+ (* b q) (* a q) (* a p)) (+ (* b p) (* a q)) p q (- count 1))))) ; (define (square x) (* x x)) ;test (= (fib 0) 0) (= (fib 1) 1) (= (fib 2) 1) (= (fib 3) 2) (= (fib 8) 21)
1.21
直接调用smallest-divisor过程:
(define (smallest-divisor n) (find-divisor n 2)) (define (find-divisor n test-divisor) (cond ((> (expt test-divisor 2) n) n) ((divisor? test-divisor n) test-divisor) (else (find-divisor n (+ test-divisor 1))))) (define (divisor? a b) (= (remainder b a) 0)) ;test (smallest-divisor 199) (smallest-divisor 1999) (smallest-divisor 19999)
执行的结果显示199和1999是素数,而19999的最小因子是7(当然这里除过1)。
1.22
(define (search-for-primes start end) (let ((num (if (even? start) (+ start 1) (+ start 2)))) (if (<= num end) ((timed-prime-test num) (search-for-primes num end)))))
注意,在这里我用了在1.3.2节引入的let过程。现在,我就可以用search-for-primes过程了,例如:
(search-for-primes 1000 1019) 1001 1003 1005 1007 1009 *** 0 1011 1013 *** 0 1015 1017 1019 *** 0
可以看到,在我的机器上检查1 000附近的素数所用的时间是0(单位是微妙)。这是由于该书写于90年代,所以在本题中我把用于测试的4个数都扩大了10 000倍,即我用到的4个数分别为100 000 000、1 000 000 000、10 000 000 000、100 000 000 000。
(search-for-primes 100000000 100000039) (newline) (search-for-primes 1000000000 1000000021) (newline) (search-for-primes 10000000000 10000000061) (newline) (search-for-primes 100000000000 100000000057)
执行结果如下:
100000001 100000003 100000005 100000007 *** 5000 100000009 100000011 100000013 100000015 100000017 100000019 100000021 100000023 100000025 100000027 100000029 100000031 100000033 100000035 100000037 *** 5000 100000039 *** 5000 ====================================== 1000000001 1000000003 1000000005 1000000007 *** 16000 1000000009 *** 15000 1000000011 1000000013 1000000015 1000000017 1000000019 1000000021 *** 16000 ====================================== 10000000001 10000000003 10000000005 10000000007 10000000009 10000000011 10000000013 10000000015 10000000017 10000000019 *** 138000 10000000021 10000000023 10000000025 10000000027 10000000029 10000000031 10000000033 *** 138000 10000000035 10000000037 10000000039 10000000041 10000000043 10000000045 10000000047 10000000049 10000000051 10000000053 10000000055 10000000057 10000000059 10000000061 *** 215000 ====================================== 100000000001 100000000003 *** 550000 100000000005 100000000007 100000000009 100000000011 100000000013 100000000015 100000000017 100000000019 *** 548000 100000000021 100000000023 100000000025 100000000027 100000000029 100000000031 100000000033 100000000035 100000000037 100000000039 100000000041 100000000043 100000000045 100000000047 100000000049 100000000051 100000000053 100000000055 100000000057 *** 552000 ====================================== 1000000000001 1000000000003 1000000000005 1000000000007 1000000000009 1000000000011 1000000000013 1000000000015 1000000000017 1000000000019 1000000000021 1000000000023 1000000000025 1000000000027 1000000000029 1000000000031 1000000000033 1000000000035 1000000000037 1000000000039 *** 1754000 1000000000041 1000000000043 1000000000045 1000000000047 1000000000049 1000000000051 1000000000053 1000000000055 1000000000057
注意,数据中的“=======”分隔符不是程序产生的,实际上程序生成的是一个newline,但是空行在博客中显示时会被省略,所以我自己添加了分隔符。从执行结果可以看出:
|------+--------+--------+-------|
|10^8 | 10^9 | 10^10 | 10^11 | => start-number
|------+--------+--------+-------|
|5 | 14 | 132 | 663 | (ms)
|5 | 13 | 133 | 549 |
|4 | 14 | 217 | 528 |
|------+--------+--------+-------|
从表中可以看出,第2列是第1列的3倍,第4列是第3列的3倍多,而(sqrt 10) = 3.16,所以从这两组数据看还比较符合预测。但是第3列与第2列的比值几乎是10,这与3.16差的太多了,我执行了好几次都是这样,为什么会有这种反常呢?(待续)。
程序在机器上的运行时间涉及很多因素,例如,当时系统的负载等,但是总体上程序的运行时间是正比于计算所需步骤的,这个也可以从前面的数据中看出。
1.23
(define (next test-divisor) (if (= test-divisor 2) 3 (+ test-divisor 2)))
运行1.22练习中的找12个素数的测试,得到如下数据:
100000007 *** 2000 100000037 *** 3000 100000039 *** 3000 ================================ 1000000007 *** 8000 1000000009 *** 9000 1000000021 *** 9000 ================================ 10000000019 *** 71000 10000000033 *** 76000 10000000061 *** 78000 ================================ 100000000003 *** 341000 100000000019 *** 249000 100000000057 *** 311000
得到表数据如下:
|------+--------+--------+-------|
|10^8 | 10^9 | 10^10 | 10^11 | => start-number
|------+--------+--------+-------|
|2 | 8 | 71 | 341 | (ms)
|3 | 9 | 76 | 249 |
|3 | 9 | 78 | 311 |
|------+--------+--------+-------|
对比1.22中的表,可以看出程序的运行速度接近于原来的1倍,严格来说是稍微小于1倍,之所以这样是因为程序里还有其他操作,而不完全是检查操作。