免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: win_hate
打印 上一主题 下一主题

SICP 习题参考答案,3.5 [复制链接]

论坛徽章:
0
41 [报告]
发表于 2009-02-03 20:04 |只看该作者

Exercise 3.69. 答案

  •   生成三元组

    • 分析:

      [1, 2,...] X [1, 2, ...] X [1,2,...] 构成的三元组,其中分量按下标非严格递增。

      可以分成两类,一类是 (1, *, * ) 的,另一类是 [2,3,...] X [2,3,...] X [2,3,...] 形成的三元组。

      第一类可以把 1 插入 [1,2,...] X [1,2,...] 形成的二元组,第二类简单地递归。所以有


      1. (define (triples s)
      2.   (define (f x)
      3.     (lambda (y) (cons x y)))
      4.   (let ((a (stream-car s)))
      5.     (cons-stream
      6.      (list a a a)
      7.      (interleave (stream-map (f a)
      8.                              (stream-cdr (pairs s s)))
      9.                  (triples (stream-cdr s))))))
      复制代码

    • 演示:


      1. > (print-stream (triples integers) 10)
      2. (1 1 1)
      3. (1 1 2)
      4. (2 2 2)
      5. (1 2 2)
      6. (2 2 3)
      7. (1 1 3)
      8. (3 3 3)
      9. (1 2 3)
      10. (2 3 3)
      11. (1 1 4)
      复制代码

    • 生成 Pythagoras 三元组

      用一个谓词函数去过滤即可


      1. (define (select x)
      2.   (define (square x) (* x x))
      3.   (let ((a (car x)) (b (cadr x))
      4.         (c (caddr x)))
      5.     (= (+ (square a) (square b))
      6.        (square c))))

      7. (define Pythagoras
      8.   (stream-filter select (triples integers)))
      复制代码

    • 演示


      1. > (print-stream Pythagoras 6)
      2. (3 4 5)
      3. (6 8 10)
      4. (5 12 13)
      5. (9 12 15)
      6. (8 15 17)
      7. (12 16 20)
      复制代码

    • 作为练习,作者无疑是想让读者使用上述过滤的方式来生成 Pythagoras 三元组。不过这个方法效率很低,事实上我无法计算出第 7 组数。我们看一下上面滤出来的第 6 组数处在流中的什么位置。


      1. (define (index x s)
      2.   (define (f s i)
      3.     (if (equal? (stream-car s)  x) i
      4.         (f (stream-cdr s) (+ i 1))))
      5.   (f s 0))
      复制代码


      1. > (index '(12 16 20) (triples integers))
      2. 583678
      复制代码

    • 另一个方法。事实上,Pythagoras 三元组是有公式的。

      如果 (a,b,c) 是一个 Pythagoras 三元组,则 (ak, bk, ck) 也是。所以只要求出互素的三元组就可以了,这样的三元组称为本原解。本原解可表示为
      (a, b, c) = (s^2-r^2, 2sr, s^2+r^2)  ;; 次序不计
      其中 (r, s)=1, a+b 为奇数, s>r


      所以我们只要用 pairs 生成二元组,并过滤出互素且分量和为奇数的序列,然后把公式 map 上去即可。


      1. (define (f x)
      2.   (let* ((a (car x))
      3.         (b (cadr x))
      4.         (aa (* a a))
      5.         (bb (* b b)))
      6.     (list (- bb aa) (* 2 a b) (+ aa bb))))

      7. (define (p x)
      8.   (let ((a (car x)) (b (cadr x)))
      9.     (and (= 1 (gcd a b))
      10.          (odd? (+ a b)))))
      11.         
      12. (define Fast-Pythagoras
      13.   (cons-stream (list 0 0 0)
      14.                (stream-map f
      15.                 (stream-filter p
      16.                  (pairs integers integers)))))
      复制代码

    • 演示:


      1. (print-stream Fast-Pythagoras 20)
      2. (0 0 0)

      3. (3 4 5)

      4. (5 12 13)

      5. (15 8 17)

      6. (35 12 37)

      7. (7 24 25)

      8. (21 20 29)

      9. (63 16 65)

      10. (99 20 101)

      11. (45 28 53)

      12. (143 24 145)

      13. (9 40 41)

      14. (195 28 197)

      15. (77 36 85)

      16. (255 32 257)

      17. (323 36 325)

      18. (117 44 125)

      19. (399 40 401)

      20. (483 44 485)

      21. (55 48 73)
      复制代码


      为了简洁,我把 (0, 0, 0) 也生成了,它是一个平凡解。前面使用直接过滤生成的 6 组数中,有一些不是本原解,所以在这里没有出现。




[ 本帖最后由 win_hate 于 2009-2-3 20:51 编辑 ]

论坛徽章:
0
42 [报告]
发表于 2009-02-03 20:12 |只看该作者

Exercise 3.70.

Exercise 3.70.  It would be nice to be able to generate streams in which the pairs appear in some useful order, rather than in the order that results from an ad hoc interleaving process. We can use a technique similar to the merge procedure of exercise 3.56, if we define a way to say that one pair of integers is ``less than'' another. One way to do this is to define a ``weighting function'' W(i,j) and stipulate that (i_1,j_1) is less than (i_2,j_2) if W(i_1,j_1) < W(i_2,j_2). Write a procedure merge-weighted that is like merge, except that merge-weighted takes an additional argument weight, which is a procedure that computes the weight of a pair, and is used to determine the order in which elements should appear in the resulting merged stream.[69] Using this, generalize pairs to a procedure weighted-pairs that takes two streams, together with a procedure that computes a weighting function, and generates the stream of pairs, ordered according to weight. Use your procedure to generate

a. the stream of all pairs of positive integers (i,j) with i < j ordered according to the sum i + j

b. the stream of all pairs of positive integers (i,j) with i < j, where neither i nor j is divisible by 2, 3, or 5, and the pairs are ordered according to the sum 2 i + 3 j + 5 i j.

[69] We will require that the weighting function be such that the weight of a pair increases as we move out along a row or down along a column of the array of pairs.

论坛徽章:
0
43 [报告]
发表于 2009-02-03 20:31 |只看该作者

Exercise 3.70. 答案

  • 分析

    注意注释 69。该注释强调了 weight (i,j) 应该分别关于 i 和 j 非严格上升。

    • 我们生成的上三角二元组可以分为两类,一类是第一行,即 (1,*) 模式,另一类为下面的行。
    • 把 weight map 到第一行,显然得到一个排序好的流(上升)。
    • 那另一个流有怎么样呢?另一个流被递归处理,只要递归成立,则它也是一个上升流。
    • 现在我们有了两个上升流。用一个按序提取的 interlever,即 merge 就可以合并成一个上升流。(其实就是 merge sort)。
    • 不过且慢,第二个流是递归处理的,它本身又是两个流的混合。为得到第二个流的第一个数,我们要把另两个流混合。但这两个流
      中又有一个是两个流的混合......
      于是我们陷入了无终止的后退,一个数都出不来。
    • 注意到 (2,2) 是第二个流中最小的,所以在递归时,以它为第一项。这样 merge 就可以马上进行,不会出现前面所说的无穷后退。
    • 所以这里把 (1,1) 或 (2,2),或 (i,i) 单独处理,有两个理由。一个是标准 scheme 的惰性不够(见 Exercise 3.68),一个是为
      了避免前面所说的无穷后退。
    • 可以看到,注释 69 很重要。如果 weight  函数选择不当,则第一个流是未排序的,按序 merge 也就无从谈起。

    按 weight 的定义, (2,2) 是这个流中的最小元素。
  • 代码


    1. (define (pairs-weight s1 s2 weight)
    2.   (if (or (stream-null? s1)) '()
    3.       (cons-stream
    4.        (list (stream-car s1) (stream-car s2))
    5.        (merge-weight
    6.         (stream-map (lambda (x) (list (stream-car s1) x))
    7.                     (stream-cdr s2))
    8.         (pairs-weight (stream-cdr s1)
    9.                       (stream-cdr s2) weight)
    10.         weight))))
    复制代码

  • a.


    1. (define (f x)
    2.   (apply + x))

    3. (define A (pairs-weight integers
    4.                         integers f))
    复制代码


    1. (take A 10)
    2. ((1 1) (1 2) (1 3) (2 2) (1 4) (2 3) (1 5) (2 4) (3 3) (1 6))
    复制代码

  • b.


    1. (define (g x)
    2.   (apply
    3.    (lambda (i j) (+ (* 2 i) (* 3 j) (* 5 i j)))
    4.    x))

    5. (define S
    6.   (stream-filter
    7.    (lambda (x)
    8.      (not (or (= 0 (modulo x 2))
    9.               (= 0 (modulo x 3))
    10.               (= 0 (modulo x 5)))))
    11.    integers))

    12. (define B (pairs-weight S S g))
    复制代码


    1. > (take B 10)
    2. ((1 1) (1 7) (1 11) (1 13) (1 17) (1 19) (1 23) (1 29) (1 31) (7 7))
    复制代码


    注意,中文版在这里有个小错误。p238 中间,

    错误:而且这里的 i 或者 j 可以被 2, 3, 5 整除
    正确:而且这里的 i 和 j 都不可以被 2, 3, 5 整除

    [ 本帖最后由 win_hate 于 2009-2-3 23:43 编辑 ]

论坛徽章:
0
44 [报告]
发表于 2009-02-03 20:36 |只看该作者

Exercise 3.71.

Exercise 3.71.  Numbers that can be expressed as the sum of two cubes in more than one way are sometimes called Ramanujan numbers, in honor of the mathematician Srinivasa Ramanujan.70 Ordered streams of pairs provide an elegant solution to the problem of computing these numbers. To find a number that can be written as the sum of two cubes in two different ways, we need only generate the stream of pairs of integers (i,j) weighted according to the sum i3  + j3 (see exercise 3.70), then search the stream for two consecutive pairs with the same weight. Write a procedure to generate the Ramanujan numbers. The first such number is 1,729. What are the next five?

论坛徽章:
0
45 [报告]
发表于 2009-02-03 20:43 |只看该作者

Exercise 3.71. 答案


  • 分析
    • 先按 w(i,j)=i^3+j^3 得到一个排序的流。
    • 再把一个函数 map 到此流上,把流中元素 (i,j) 变为 (i^3+j^3, (i,j))
    • 再把另一个函数 map 到新的流上,此函数以重量相同为标准,把相邻的项合并成 (总项数,重量,项 1, 项 2 ....)

  • 代码


    1. (define (f x)
    2.   (let ((a (car x))
    3.         (b (cadr x)))
    4.     (+ (* a a a) (* b b b))))

    5. (define Ramanujans-stream
    6.   (stream-map
    7.    (lambda (x) (list (f x) x))
    8.    (pairs-weight integers integers f)))

    9. (define (group-with-weight s)
    10.   (define (g s w cur cnt)
    11.     (let ((a (stream-car s)))
    12.       (if (= (car a) w)
    13.           (g (stream-cdr s) w
    14.              (cons (cadr a) cur) (+ cnt 1))
    15.           (cons-stream
    16.            (cons cnt (cons w cur))
    17.            (g (stream-cdr s) (car a) (cdr a) 1)))))
    18.   (let ((b (stream-car s)))
    19.     (g (stream-cdr s) (car b)
    20.        (cdr b) 1)))

    21. (define R
    22.   (stream-filter (lambda (x) (= (car x) 2))
    23.                  (group-with-weight Ramanujans-stream)))
    复制代码

  • 演示

    1. > (print-stream R 10)

    2. (2 1729 (9 10) (1 12))

    3. (2 4104 (9 15) (2 16))

    4. (2 13832 (18 20) (2 24))

    5. (2 20683 (19 24) (10 27))

    6. (2 32832 (18 30) (4 32))

    7. (2 39312 (15 33) (2 34))

    8. (2 40033 (16 33) (9 34))

    9. (2 46683 (27 30) (3 36))

    10. (2 64232 (26 36) (17 39))

    11. (2 65728 (31 33) (12 40))
    复制代码



[ 本帖最后由 win_hate 于 2009-2-3 21:04 编辑 ]

论坛徽章:
0
46 [报告]
发表于 2009-02-03 20:44 |只看该作者

Exercise 3.72.

Exercise 3.72.  In a similar way to exercise 3.71 generate a stream of all numbers that can be written as the sum of two squares in three different ways (showing how they can be so written).

论坛徽章:
0
47 [报告]
发表于 2009-02-03 20:46 |只看该作者

Exercise 3.72. 答案

  • 与上题类似
  • 代码

    1. (define (g x)
    2.   (let ((a (car x))
    3.         (b (cadr x)))
    4.     (+ (* a a) (* b b))))

    5. (define sum-of-square
    6.   (stream-map (lambda (x) (list (g x) x))
    7.               (pairs-weight integers integers g)))

    8. (define square-of-tree
    9.   (stream-filter (lambda (x) (= (car x) 3))
    10.                  (group-with-weight sum-of-square)))
    复制代码

  • 演示


    1. > (print-stream square-of-tree 10)

    2. (3 325 (10 15) (6 17) (1 18))

    3. (3 425 (13 16) (8 19) (5 20))

    4. (3 650 (17 19) (11 23) (5 25))

    5. (3 725 (14 23) (10 25) (7 26))

    6. (3 845 (19 22) (13 26) (2 29))

    7. (3 850 (15 25) (11 27) (3 29))

    8. (3 925 (21 22) (14 27) (5 30))

    9. (3 1025 (20 25) (8 31) (1 32))

    10. (3 1250 (25 25) (17 31) (5 35))

    11. (3 1300 (20 30) (12 34) (2 36))
    复制代码

    [ 本帖最后由 win_hate 于 2009-2-3 21:02 编辑 ]

论坛徽章:
0
48 [报告]
发表于 2009-02-11 09:58 |只看该作者

Exercise 3.73.

Exercise 3.73.  

                                          



Figure 3.33:  An RC circuit and the associated signal-flow diagram.

We can model electrical circuits using streams to represent the values of currents or voltages at a sequence of times. For instance, suppose we have an RC circuit consisting of a resistor of resistance R and a capacitor of capacitance C in series. The voltage response v of the circuit to an injected current i is determined by the formula in figure 3.33, whose structure is shown by the accompanying signal-flow diagram.

Write a procedure RC that models this circuit. RC should take as inputs the values of R, C, and dt and should return a procedure that takes as inputs a stream representing the current i and an initial value for the capacitor voltage v0 and produces as output the stream of voltages v. For example, you should be able to use RC to model an RC circuit with R = 5 ohms, C = 1 farad, and a 0.5-second time step by evaluating (define RC1 (RC 5 1 0.5)). This defines RC1 as a procedure that takes a stream representing the time sequence of currents and an initial capacitor voltage and produces the output stream of voltages.

[ 本帖最后由 win_hate 于 2009-2-11 10:16 编辑 ]

论坛徽章:
0
49 [报告]
发表于 2009-02-11 10:15 |只看该作者

Exercise 3.73. 答案

  • 代码

    按图 3-33 写的


    1. (define (RC R C dt)
    2.   (lambda (IS v0)
    3.     (let* ((s1 (scale-stream IS (/ 1 C)))
    4.            (s2 (integral s1 v0 dt))
    5.            (s3 (scale-stream IS R)))
    6.       (add-streams s2 s3))))

    7. (define RC1 (RC 5 1 0.5))
    复制代码

  • 演示


    1. > (define s (cons-stream 1 s))

    2. > (define v (RC1 s 1))

    3. > (take v 10)
    4. (6 6.5 7.0 7.5 8.0 8.5 9.0 9.5 10.0 10.5)
    复制代码

论坛徽章:
0
50 [报告]
发表于 2009-02-11 10:17 |只看该作者

Exercise 3.74.

Exercise 3.74.  Alyssa P. Hacker is designing a system to process signals coming from physical sensors. One important feature she wishes to produce is a signal that describes the zero crossings of the input signal. That is, the resulting signal should be + 1 whenever the input signal changes from negative to positive, - 1 whenever the input signal changes from positive to negative, and 0 otherwise. (Assume that the sign of a 0 input is positive.) For example, a typical input signal with its associated zero-crossing signal would be

...1  2  1.5  1  0.5  -0.1  -2  -3  -2  -0.5  0.2  3  4 ...... 0  0    0  0    0     -1  0   0   0     0    1  0  0 ...

In Alyssa's system, the signal from the sensor is represented as a stream sense-data and the stream zero-crossings is the corresponding stream of zero crossings. Alyssa first writes a procedure sign-change-detector that takes two values as arguments and compares the signs of the values to produce an appropriate 0, 1, or - 1. She then constructs her zero-crossing stream as follows:

(define (make-zero-crossings input-stream last-value)
  (cons-stream
   (sign-change-detector (stream-car input-stream) last-value)
   (make-zero-crossings (stream-cdr input-stream)
                        (stream-car input-stream))))

(define zero-crossings (make-zero-crossings sense-data 0))

Alyssa's boss, Eva Lu Ator, walks by and suggests that this program is approximately equivalent to the following one, which uses the generalized version of stream-map from exercise 3.50:

(define zero-crossings
  (stream-map sign-change-detector sense-data <expression>))

Complete the program by supplying the indicated <expression>.
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP