SICP习题解答1.20-1.28

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值