ex1.20-1.22
#lang racket
; exercise 1.20
;; 正则序求值(gcd 206 40) 18次(判断14次 求值4次)
;; 应用序4次
; exercise 1.21
(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 (square n)
(* n n))
;; > (smallest-divisor 199)
;; 199
;; > (smallest-divisor 1999)
;; 1999
;; > (smallest-divisor 19999)
;; 7
; exercise 1.22
(define (timed-prime-test n)
(start-prime-test n (current-inexact-milliseconds))) ;; runtime需要改成current-inexact-milliseconds
(define (start-prime-test n start-time)
(if (prime? n)
(report-prime (- (current-inexact-milliseconds) start-time) n)
#f)) ;; 必须有else部分,否则会报错
(define (report-prime elapsed-time n)
(newline)
(display n)
(display " *** ")
(display elapsed-time))
(define (prime? n)
(= n (smallest-divisor n)))
(define (search-for-primes b e)
(search (if (even? b) (+ b 1) b) (if (even? e) (- e 1) e)))
(define (search cur e)
(cond ((<= cur e) (timed-prime-test cur) (search (+ cur 2) e)))) ;; 如果使用if必须把两个表达式分开来
(define (even? n)
( = (remainder n 2) 0))
ex1.23
#lang racket
; exercise 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 (divides? a b)
(= (remainder b a) 0))
(define (square n)
(* n n))
(define (next n)
(if (= n 2)
3
(+ n 2)))
(define (timed-prime-test n)
(start-prime-test n (current-inexact-milliseconds)))
(define (start-prime-test n start-time)
(if (prime? n)
(report-prime (- (current-inexact-milliseconds) start-time) n)
#f))
(define (report-prime elapsed-time n)
(newline)
(display n)
(display " *** ")
(display elapsed-time))
(define (prime? n)
(= n (smallest-divisor n)))
;; 执行速度没有快一倍,可能的原因是next过程执行需要时间,而原来只进行了+操作,时间比大概在1.5~2
ex1.24-1.28
#lang racket
; exercise 1.24
(define (timed-prime-test n)
(start-prime-test n (current-inexact-milliseconds)))
(define (start-prime-test n start-time)
(if (fast-prime? n 100)
(report-prime (- (current-inexact-milliseconds) start-time) n)
#f))
(define (report-prime elapsed-time n)
(newline)
(display n)
(display " *** ")
(display elapsed-time))
(define (fast-prime? n times)
(cond ((= times 0) #t)
((fermat-test n) (fast-prime? n (- times 1)))
(else #f)))
(define (fermat-test n)
(define (try-it a)
(= (expmod a n n) a))
(try-it (+ 1 (random (if (<= n 4294967087) (- n 1) 4294967087)))))
(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 (square n)
(* n n))
(timed-prime-test 10000000019) ;; 10000000019 *** 496.0
(timed-prime-test 100000000000000000039) ;; 100000000000000000039 *** 919.0
;; 10e10与10e20运行时间大概是两倍关系 符合对数增长规律
; exercise 1.25
;; 修改后没有利用(a*b)%m=((a%m)*(b%m))%m这条可以减小计算量的规则,所以会更加耗时
; exercise 1.26
;; 重复计算
; exercise 1.27
(define (test n)
(test-f n 1))
(define (test-f n c)
(if (= (expmod c n n) c)
(test-f n (+ c 1))
#f)
#t)
(test 561)
(test 1105)
(test 1729)
(test 2465)
(test 2821)
(test 6601)
;; 上面的测试返回都是#t,说明这些都是Carmichael数
; exercise 1.28
(define (miller-rabin-test n)
(define (try-it a)
(= (miller-rabin-expmod a (- n 1) n) 1))
(try-it (+ 1 (random (- n 1)))))
(define (miller-rabin-expmod base exp m) ;; miller-rabin-expmod返回0表示失败,即存在非平凡平凡根
(define (check-it n) ;; check-it检查n是否是非平凡平凡跟,若是返回0(即失败),否则返回(n*n)%m,继续计算
(define (check-pingfan n square-n)
(define (pingfan? n)
(and (not (= n 1))
(not (= n (- m 1)))
(= square-n 1)))
(if (pingfan? n)
0
square-n))
(check-pingfan n (remainder (square n) m)))
(cond ((= exp 0) 1)
((even? exp) (check-it (miller-rabin-expmod base (/ exp 2) m)))
(else (remainder (* base (miller-rabin-expmod base (- exp 1) m)) m))))
(define (fast-lr-prime? n times)
(cond ((= times 0) #t)
((miller-rabin-test n) (fast-prime? n (- times 1)))
(else #f)))
(define (lr-prime? n)
(fast-lr-prime? n 1000)) ;; 测试1000次,次数少的话可能会不准确
(lr-prime? 2) ; #t
(lr-prime? 5) ; #t
(lr-prime? 7) ; #t
(lr-prime? 13) ; #t
(lr-prime? 23) ; #t
(lr-prime? 53) ; #t
(lr-prime? 561) ; #f
(lr-prime? 1105) ; #f
(lr-prime? 1729) ; #f
(lr-prime? 2465) ; #f
(lr-prime? 2821) ; #f
(lr-prime? 6601) ; #f