SICP 1.23-1.26体会
1.23 代码修改非常easy, 关键是时间。 电脑上算了一下。 100000000下面全是0。 開始还以为代码写错了。
最后没办法, 用1e10 1e11来计算。 发现比 1e11 1e12快1.2-1.5之间。
比2小。
想了半天也给不出非常合理的解析。
開始以为是对3 5 7 取余数 比 4 6 8 要慢, 測试了一下,发现也不是这么一回事。网上有人怀疑是函数调用花了一定时间做if 推断, 老实说这东西性能影响也不应有这么大。
如今唯一想到的,就是编译器做了一些优化,导致性能不全然取决于调用次数。
这题目。网上也没找到非常合理的分析。
1.24 也非常遗憾。 開始将times设为10。 计算时间1e10下面全然是0. 后面没办法,将times设为10000, 结果发现时间也非常漂浮不定。
有时候, 1e12-1e13 比 1e11-1e12计算速度还快。
仅仅能说random导致性能非常随机了。
1.25 理论上肯定是对的, 时间上就悲剧了。我这边运行 100000000 1000000000区间,直接死机。
根本原因,还是我们的CPU是32或64位的。 不是无限位。
1.26 这个题目算法导论有清晰的解析。套用算法导论的公式T(n) = 2T(n/2) 可知道 T(n) = Theta(n)
坦率地说, SICP不是学算法的好书。 也不是讲数据结构的好书。
个人代码例如以下:
1.23
(define (search-for-primes-new start end count)
(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))
0))
(define (report-prime elapsed-time)
(display " *** ")
(display elapsed-time)
1)
(define (prime? n)
(= n (smallest-divisor-new n)))
(define (smallest-divisor-new n)
(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 (next test-divisor)
(if (= test-divisor 2)
3
(+ test-divisor 2)))
(find-divisor n 2))
(define (search-iter start end count)
(if (or (> start end) (= count 0))
0
(if (= (timed-prime-test start) 1)
(search-iter (+ start 1) end (- count 1))
(search-iter (+ start 1) end count))))
(search-iter start end count))
1.24
(define (search-for-primes-new start end count)
(define (timed-prime-test n)
(newline)
(display n)
(start-prime-test n (runtime)))
(define (start-prime-test n start-time)
(if (fast-prime? n 10000)
(report-prime (- (runtime) start-time))
0))
(define (report-prime elapsed-time)
(display " *** ")
(display elapsed-time)
1)
(define (search-iter start end count)
(if (or (> start end) (= count 0))
0
(if (= (timed-prime-test start) 1)
(search-iter (+ start 1) end (- count 1))
(search-iter (+ start 1) end count))))
(search-iter start end count))
(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 (fast-prime?
n times)
(cond ((= times 0) true)
((fermat-test n) (fast-prime?
n (- times 1)))
(else false)))
(define (fermat-test n)
(define (try-it a)
(= (expmod a n n) a))
(try-it (+ 1 (random (- n 1)))))
1.25
(define (search-for-primes-25 start end count)
(define (timed-prime-test n)
(newline)
(display n)
(start-prime-test n (runtime)))
(define (start-prime-test n start-time)
(if (fast-prime? n 10000)
(report-prime (- (runtime) start-time))
0))
(define (report-prime elapsed-time)
(display " *** ")
(display elapsed-time)
1)
(define (search-iter start end count)
(if (or (> start end) (= count 0))
0
(if (= (timed-prime-test start) 1)
(search-iter (+ start 1) end (- count 1))
(search-iter (+ start 1) end count))))
(search-iter start end count))
(define (expmod base exp m)
(remainder (fast-expt base exp) m))
(define (fast-expt base exp)
(cond ((= exp 0) 1)
((even?
exp)
(square (fast-expt base (/ exp 2))))
(else
(* base (fast-expt base (- exp 1))))))
(define (fast-prime? n times)
(cond ((= times 0) true)
((fermat-test n) (fast-prime?
n (- times 1)))
(else false)))
(define (fermat-test n)
(define (try-it a)
(= (expmod a n n) a))
(try-it (+ 1 (random (- n 1)))))