SICP 1.21-1.28

来源:互联网 发布:淘宝内裤真人秀在哪看 编辑:程序博客网 时间:2024/05/18 21:44

寻找因子法

(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 (+ test-divisor 1)))))(define (divides? a b)  (= (remainder b a) 0))(define (prime? n)  (= n (smallest-divisor n)))

练习1.21

(smallest-divisor 199)199(smallest-divisor 1999)1999(smallest-divisor 19999)7

练习1.22
检测prime的运行时间

(define (runtime)        (time->seconds (current-time)))(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 (search-for-primes start count)  (define (search-for-primes-iter n count)    (if (= 0 count)        (newline)        (if (prime? n)            (begin (timed-prime-test n)                   (search-for-primes-iter (+ n 2) (- count 1)))            (search-for-primes-iter (+ n 2) count))))  (if (odd? start)      (search-for-primes-iter start count)      (search-for-primes-iter (+ start 1) count)))
> (search-for-primes 1000 3)1009 *** 2.8848648071289062e-51013 *** 2.6702880859375e-51019 *** 2.6464462280273438e-5
> (search-for-primes 10000 3)10007 *** 8.463859558105469e-510009 *** 8.225440979003906e-510037 *** 8.988380432128906e-5
> (search-for-primes 100000 3)100003 *** 2.63214111328125e-4100019 *** 2.5534629821777344e-4100043 *** 2.7489662170410156e-4
> (search-for-primes 1000000 3)1000003 *** 8.673667907714844e-41000033 *** 8.487701416015625e-41000037 *** 8.304119110107422e-4
> (search-for-primes 10000000 3)10000019 *** .001893043518066406210000079 *** .002126693725585937510000103 *** .001911163330078125

练习1.23

(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 test-divisor)  (if (= test-divisor 2)      3      (+ test-divisor 2)))(define (divides? a b)  (= (remainder b a) 0))(define (prime? n)  (= n (smallest-divisor n)))
> (search-for-primes 1000 3)1009 *** 2.0265579223632812e-51013 *** 2.1696090698242188e-51019 *** 2.1696090698242188e-5
> (search-for-primes 10000 3)10007 *** 6.079673767089844e-510009 *** 5.698204040527344e-510037 *** 5.9604644775390625e-5
> (search-for-primes 100000 3)100003 *** 1.6808509826660156e-4100019 *** 1.633167266845703e-4100043 *** 1.6307830810546875e-4
> (search-for-primes 1000000 3)1000003 *** 5.249977111816406e-41000033 *** 5.125999450683594e-41000037 *** 5.097389221191406e-4
> (search-for-primes 10000000 3)10000019 *** .001642942428588867210000079 *** .001635313034057617210000103 *** .0010938644409179688

练习1.24

费马定理: 如果n是一个素数,a是小于n的任意正整数,那么a的n次方与a模n同余。
(如果两个数除以n的余数相同,称为模n同余)
0 < a < n => a n   mod n = a mod n

;计算一个数的幂对另一个数取模的结果(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 (fermat-test n)  (define (try-it a)    (= (expmod a n n) a))  (try-it (random-integer n)));random-integer是Gambit-c提供的函数(define (fast-prime? n times)  (cond ((= times 0) #t)        ((fermat-test n) (fast-prime? n (- times 1)))        (else #f)))
(define (runtime)        (time->seconds (current-time)))(define (timed-prime-test n)  (newline)  (display n)  (start-prime-test n (runtime)))(define (start-prime-test n start-time)  (if (fast-prime? n 5)      (report-prime (- (runtime) start-time))))(define (report-prime elapsed-time)  (display " *** ")  (display elapsed-time))(define (search-for-primes start count)  (define (search-for-primes-iter n count)    (if (= 0 count)        (newline)        (if (fast-prime? n 3)            (begin (timed-prime-test n)                   (search-for-primes-iter (+ n 2) (- count 1)))            (search-for-primes-iter (+ n 2) count))))  (if (odd? start)      (search-for-primes-iter start count)      (search-for-primes-iter (+ start 1) count)))
> (search-for-primes 1000 3)1009 *** 7.772445678710938e-51013 *** 8.20159912109375e-51019 *** 8.988380432128906e-5
> (search-for-primes 10000 3)10007 *** 1.010894775390625e-410009 *** 9.560585021972656e-510037 *** 9.894371032714844e-5
> (search-for-primes 100000 3)100003 *** 1.1563301086425781e-4100019 *** 1.1944770812988281e-4100043 *** 1.1801719665527344e-4
> (search-for-primes 1000000 3)1000003 *** 1.354217529296875e-41000033 *** 1.3875961303710938e-41000037 *** 1.361370086669922e-4
> (search-for-primes 10000000 3)10000019 *** 1.5854835510253906e-410000079 *** 1.671314239501953e-410000103 *** 1.6617774963378906e-4

练习1.25

(define (expmod base exp m)  (remainder (fast-expt base exp) m))

这样会比1.24运行的慢


练习1.26
(expmod base (/ exp 2) m)被递归两次


练习1.27
能够骗过费马检查的数,称为Carmichael数,在100000000之内有255个Carmichael数,其中最小的几个是561、1105、1729、2465、2821和6601。

> (fast-prime? 561 10)#t> (fast-prime? 1105 5)#t> (fast-prime? 1729 5)#t> (fast-prime? 2465 5)#t> (fast-prime? 2821 5)#t> (fast-prime? 6601 5)#t

练习1.28

(define (mr n)  (define (test-all-a count result)    (display count) (display result) (newline)    (if result      (if (> count 1)        (test-all-a (- count 1) (try-it (- count 1))) ;test all a, 1 < a < n        #t)      #f))  (define (try-it a)    (= (expmod a (- n 1) n) 1))  (test-all-a n #t)) (define (expmod base expo m)  (cond ((= expo 0) 1)        ((even? expo) (let* ((x (expmod base (/ expo 2) m)) (r (remainder (square x) m)))                          (if (and (= r 1) (not (= x 1)) (not (= x (- m 1)))) 0 r)))        (else (remainder (* base (expmod base (- expo 1) m))                         m))))
0 0
原创粉丝点击