SICP读书笔记及题解 Ch1

本文详细解答了SICP第一章中的多个习题,包括数值计算中的迭代法改进、条件表达式的不同解释方式及其影响等核心内容,并针对sqrt和cube-root函数的实现进行了深入探讨。

Ch1 题解

Ex 1.3

(define (square x) (* x x)) 
(define (square-larger-two-numbers a b c)
  (define (large-number a b) 
    (if (> a b) a b)) 
  (define (small-number a b) 
    (if (< a b) a b)) 
  (define (largest-number a b c) 
    (large-number a (large-number b c))) 
  (define (middle-number a b c) 
    (small-number a (large-number b c))) 
  (+ (square (largest-number a b c)) (square (middle-number a b c)))
)

Ex 1.5

采用normal-order evaluation的解释器会将(test 0 (p))先展开为(if (= x 0) 0 (p)),之后判断x是否为0,本例中x为0,因此返回0,而不解析(p)。

而在application-order evaluation的解释器中,(test 0 (p))里的(p)会首先被求值并带入到test里作参数,如此一来程序就会陷入对p无限的调用之中。

Ex 1.6

对于“特殊的”(if predicate then-clause else-clause),应用序解释器在解释的过程中会首先求解predicate,如果predicate返回真,则执行then-clause,否则执行else-clause。在得到predicate的结果之前不会操作then-clause和else-clause。

而对于本题中定义的new-if:

(define (new-if predicate then-clause else-clause)
  (cond (predicate then-clause)
        (else else-clause)))

可以看到new-if实际上是一个过程(procedure),那么应用序解释器会首先将predicate、then-clause和else-clause这三个参数求解,然后代入到new-if里。

如果在then-clause或者else-clause中发生直接的或者间接的对new-if的递归调用,就会出现解释器陷入无限递归的情况。因为解释器首先将三个参数都进行求解,然后才进入cond这段代码,则递归发生在了判断递归条件之前,无法产生递归边界。

对应正则序的解释器,则会发生表达式无限展开的情况。

Ex 1.7

求(sqrt x)中用到的good-enough?在给定x过小或者过大时都会出现问题。

过小的情况

如果给定数据过小,比如good-enough?的阈值为0.0001,而要开平方根的数是0.00000001,那么在迭代进行到0.0078时,其平方为0.00006,已经小于阈值,而0.00000001本身就远小于阈值,两者之间的差值自然小于阈值,迭代结束。而显然0.00000001的平方根是0.0001,显然0.0078作为结果误差过大。

过大的情况

由于浮点数精度有限,当指数过大时,阈值条件将无法达到,从而陷入无限的迭代中。
比如对于1.6e151,当迭代进行到guess为4.0000000000000005e+075时,guess的平方为1.6000000000000006e+151,与1.6e151作差得到5.8e135,显然是不满足阈值条件的;拿现在的guess去做improve,我们看到(/ x guess)得到4e75,对4e75和4.0000000000000005e+075求平均数,由于浮点数精度有限,这个平均数无法表示成4.00000000000000025e+075,得到结果仍然是4.0000000000000005e+075,于是又进入下一次迭代。

关于浮点数的表示,参见IEEE 754

新的策略

对于误差过大的问题,可以通过减小阈值来保证结果的精确度。但是阈值过小也会使计算收敛的时间变长,计算速度变慢。

对于数据过大导致无法终止迭代的问题,这里采用一种新的策略来实现good-enough?:不再检测guess的平方与给定值的差值大小是否和要求,而是去检测两次迭代所产生的guess之间的差值,当两次guess相差足够小时,就可以认为算法已经收敛。

代码如下:

(define (average x y) (/ (+ x y) 2))
(define (sqr x) (* x x))
(define (abs x)
  (if (< x 0)
      (- x)
      x))
(define (good-enough? guess1 guess2)
  (< (abs (- guess1 guess2)) 0.0001))
(define (improve x guess)
  (average guess (/ x guess)))
(define (sqrt-iter x guess)
  (if (good-enough? (improve x guess) guess)
      guess
      ((lambda ()
         (display guess)
         (newline)
         (sqrt-iter x (improve x guess))))))
(define (sqrt x)
  (sqrt-iter x 1.0))
(sqrt 1.6e151)

Ex 1.8

(define (cube x) (* x x x))
(define (square x) (* x x))
(define (abs x)
  (if (< x 0)
      (- x)
      x))
(define (cube-root x)
  (define (improve x guess)
    (/ (+ (/ x (square guess)) (* 2 guess)) 3))
  (define (good-enough? x guess)
    (< (abs (- (cube guess) x)) 0.0001))
  (define (cube-root-iter x guess)
    (if (good-enough? x guess)
        guess
        (cube-root-iter x (improve x guess))))
  (cube-root-iter x 1.0))
(cube-root 27.0)

转载于:https://www.cnblogs.com/foolyou/p/sicp-ch1.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值