1.23

练习 1.23: 在本节开始时给出的那个 smallest-divisor 过程做了许多无用检查: 在它检查了一个数是否能被 2 整除之后,实际上已经完全没有必要再检查它是否能被任何偶数整除了。这说明 test-divisor 所用的值不应该是 2,3,4,5,6,……,而应该是 2,3,5,7,9,……。 请实现这种修改。其中应定义一个过程 next,用 2 调用它时返回 3,否则就返回其输入值加 2.修改 smallest-divisor 过程,使它去使用 (next test-divisor) 而不是 (+ test-divisor 1)。让 timed-prime-test 结合这个 smallest-divisor 版本,运行练习 1.22 里的 12 个找素数的测试。因为这一修改使检查的步数减少一半,你可能期望它的运行速度快一倍。实际情况符合这一预期吗?如果不符合,你所观察到的两个算法速度的比值是什么?你如何解释这一比值不是 2 的事实?

分别找出大于 1 000、 10 000、 100 000、 1 000 000 的三个最小素数

(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 (sqrt-iter lastGuess guess x) (if (good-enough? lastGuess guess) guess (sqrt-iter guess (improve guess x) x) ) ) (define (good-enough? lastGuess guess) (< (abs (- lastGuess guess)) 0.001) ) (define (improve guess x) (average guess (/ x guess))) (define (average x y) (/ (+ x y) 2)) (define (report-prime n elapsed-time) (newline) (display n) (display " _\*\* ") (display elapsed-time) (display ", 它的 $\\sqrt{n}$ 倍时间是 ") (display (_ elapsed-time (sqrt-iter 1 10 elapsed-time))) ) (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 (next current) (if (= current 2) 3 (+ current 2)) ) (define (divides? a b) (= (remainder b a) 0)) (define (square x) (\* x x)) (define (timed-prime-test-between n1 n2 found) (if (timed-prime-test n1) (if (or (> found 1) (> n1 n2)) (display " 测试结束! ") (timed-prime-test-between (+ n1 1) n2 (+ found 1)) ) (if (> n1 n2) (display " 测试结束! ") (timed-prime-test-between (+ n1 1) n2 found) ) ) ) (newline) (display "大于 1000 的三个最小素数:") (timed-prime-test-between 1001 9999 0) (newline) (newline) (display "大于 10 000 的三个最小素数:") (timed-prime-test-between 10001 99999 0) (newline) (newline) (display "大于 100 000 的三个最小素数:") (timed-prime-test-between 100001 999999 0) (newline) (newline) (display "大于 1 000 000 的三个最小素数:") (timed-prime-test-between 1000001 9999999 0) (newline)

以该测试机器为例:

大于 优化前 优化后 比值
1000 2 1 2
10 000 2 2 1
100 000 6 4 1.5
1 000 000 14 9 1.6

可以看到优化后的速度并没有快一倍,而是在 1.5 倍左右。

原因是虽然检查的步骤少了一半,但是整个寻找过程中,检查的步骤没有占到全部,还有一些例行的步骤在。并且相对于优化前的步骤,多出了 next 这个决定下一个检查数的步骤,不再是简单地累加 1 了,而是有个 if 判断。

results matching ""

    No results matching ""