SICP习题解答:第一章(上)

?View Code SCHEME
;; 1.1-2 略
 
;; 1.3
(define (greater-two a b c)
  (-
   (+ a b c)
   (min a b c)))
; 或
(define (greater-two a b c)
  (cond ((and (> b a) (> c a))
         (+ b c))
        ((and (> a b) (> c b))
         (+ a c))
        (else (+ a b))))
 
;; 1.4 (if (> b 0) + -) 根据b的正负性返回函数+或-。
 
;; 1.5 函数p的定义 (define (p) (p)) 是不断递归调用自己,所以欲对其进行求值/展开会产生死循环。调用 (test 0 (p)) 时,若采用应用序求值,会先对函数的参数,包括 (p) 求值,因而产生死循环,无法输出结果;若采用正则序求值,则由于 (p) 的值事实上不会被展开,故会正常返回0。
 
;; 1.6 将在调用函数 new-if 时,应用序要求先算出其所有参数的值,new-if 的后两个参数——代表 if 的两个分支的代码都将被执行。所以 (sqrt-iter guess x) 必然需要调用 (sqrt-iter (improve guess x) x),这导致死循环。
 
;; 1.7
(define (sqrt x)
  (define (sqrt-iter guess)
    (define (good-enough?)
      (< (abs (/ (- (* guess guess) x) x)) 0.001))
    (define (improve)
      (define (average a b)
        (/ (+ a b) 2))
      (average guess (/ x guess)))
    (if (good-enough?)
        guess
        (sqrt-iter (improve))))
  (sqrt-iter 1.0))
 
;; 1.8
(define (cube-root x)
  (define (iter guess)
    (define (good-enough?)
      (< (abs (/ (- (* (* guess guess) guess) x) x)) 0.001))
    (define (improve)
      (/ (+ ( / x (* guess guess)) (* 2 guess)) 3))
    (if (good-enough?)
        guess
        (iter (improve))))
  (iter 1.0))
 
;; 1.9 第一个过程是递归的,表达式被递归地逐渐展开再合并;第二个过程中的递归是尾递归,不妨理解为迭代的。
 
;; 1.10 (f n)是n的2倍,(g n)是2的n次方,(h n)是2的(h (- n 1))次方。
 
;; 1.11
; 递归方式
(define (f n)
  (if (< n 3) n
      (+ (f (- n 1))
         (* 2 (f (- n 2)))
         (* 3 (f (- n 3))))))
 
; 迭代方式
 
(define (f n)
  (define (iter a b c i)
    (if (= i n) c
        (iter b c
              (+ (* 3 a) (* 2 b) c)
              (+ i 1))))
  (if (< n 3) n
      (iter 0 1 2 2)))
 
;; 1.12
(define (C n i)
  (if (or (= i 0) (= i n))
      1
      (+ (C (- n 1) (- i 1)) (C (- n 1) i))))
 
;; 1.13 可利用归纳法和定义直接证。
 
;; 1.14 空间复杂度为 O(amount),因为任何时刻调用链的长度(栈上的函数数量)不超过 amount+1;时间复杂度为 O(amount * result),因为每得到一种方案都调用一次 (cc 0 kinds-of-coins)。
 
;; 1.15 空间与时间复杂度均为O(log a)。
 
;; 1.16 prod*a^m是不变量。
(define (fast-expt b n)
  (define (iter prod a m)
    (if (= 0 m) prod
        (if (= 0 (remainder m 2))
            (iter prod (* a a) (/ m 2))
            (iter (* prod a) (* a a) (/ (- m 1) 2)))))
  (iter 1 b n))
 
;; 1.17
(define (fast-multi a b)
  (if (= 1 a) b
      (if (= 0 (remainder a 2))
          (double (fast-multi (halve a) b))
          (+ b (double (fast-multi (halve (- a 1)) b))))))
 
;; 1.18
(define (fast-multi a b)
  (define (iter sum i n)
    (if (= 0 n) sum
        (if (= 0 (remainder n 2))
            (iter sum (double i) (halve n))
            (iter (+ sum i) (double i) (halve (- n 1))))))
  (iter 0 a b))
 
;; 1.19 p’ = pp + qq,q’ = qq + 2pq。
 
;; 1.20 应用序需要4次;正则序需要更多,没仔细数,因为gcd函数体中出现了三处b,当b是调用remainder的形式时,它需要被展开若干次。
 
;; 1.21 略。
 
;; 1.22-24 我用的DrScheme没有定义runtime……555
 
;; 1.25 如果不在计算乘幂时随时取模,每次乘法将由于被乘数位数的迅速增长而不能被看做单位时间的原子操作。
 
;; 1.26 每次(expmod base exp m)当exp为正偶数时会调用两次而非一次(expmod base exp m),f(N)=2*f(N/2)+Θ(1)导致f(N)=Θ(N),而原始版本的f(N)=f(N/2)+Θ(1)导致f(N)=Θ(log N)。
 
;; 1.27 以下程序中,(find-carmichael n)找出不超过n的Carmichael数
 
(define (prime? n)
  (define (iter i)
    (cond
      ((> (square i) n) true)
      ((= 0 (remainder n i)) false)
      (else (iter (+ i 1)))))
  (iter 2))
 
(define (carmichael? n)
  (define (iter i)
    (cond
      ((= i n) true)
      ((not (= i (expmod i n n))) false)
      (else (iter (+ i 1)))))
  (and (not (prime? n)) (iter 2)))
 
(define (find-carmichael n)
  (define (iter i)
    (cond ((carmichael? i) (display i) (display "\n")))
    (cond ((< i n) (iter (+ i 1)))))
  (iter 2))
 
;; 1.28
(define (miller-rabin n)
  (define (exp-iter prod base exp)
    (cond ((and (< 1 prod) (< prod (- n 1)) (= (remainder (* prod prod) n) 1)) 0)
          ((= 0 exp) prod)
          (else (if (even? exp)
                    (exp-iter
                     prod
                     (remainder (* base base) n)
                     (/ exp 2))
                    (exp-iter
                     (remainder (* prod base) n)
                     (remainder (* base base) n)
                     (/ (- exp 1) 2))))))
  (define (check i)
    (= 1 (exp-iter 1 i (- n 1))))
  (define (check-iter i)
    (cond ((= i 0) true)
          (else (if (check (+ 2 (random (- n 3))))
                    (check-iter (- i 1)) false))))
  (or (= 2 n) (= 3 n)
      (and (< 2 n) (= 1 (remainder n 2)) (check-iter 20))))

5 Comments »

  1. SGi Said,

    November 26, 2008 @ 23:43

    WP里面不是有个很好用的代码插件么..WP-Codebox用Geshi做的..效果不错..支持的语言高亮大概上60种了..

  2. mces89 Said,

    December 7, 2008 @ 12:28

    1.7运行不了,提示是reference to an identifier before its definition: cube-root,我自己写了个也是类似的错误提示,大牛帮忙看看

  3. Karl Said,

    January 1, 2009 @ 14:44

    1.3的第二个程序有个小bug,比如输入为1,1,2的时候程序结果不对
    DrScheme有个current-milliseconds可以代替runtime的

  4. Karl Said,

    January 1, 2009 @ 14:54

    哦,貌似millisecond精度不够……

  5. XeCycle Said,

    January 6, 2009 @ 12:31

    没有看到上面的说明还以为是lisp呢,看来远离编程一段时间很快就落伍了。比赛完毕了,总有这苦恼。

Leave a Comment