SICP学习笔记(2.1.4)
周银辉
1,练习2.7
要得到答案,需注意到文中的一段话“Alyssa假设有一种称为区间的抽象对象,这种对象有两个端点,一个上界一个下界”,很明显,一个区间是由上界和下界来定义的,正如我们说平面上一个点是由其X坐标与Y坐标来定义的一样,所以,区间的定义函数便可写成:
(define (make-interval a b) (cons a b))
那么很自然的,求上界和下界的函数就如下了:
;定义上界
(define (lower-bound x)
(car x))
;定义下界
(define (upper-bound x)
(cdr x))
2,练习2.8
;定义区间减法
(define (sub-interval x y)
(make-interval (- (lower-bound x) (lower-bound y))
(- (upper-bound x) (upper-bound y))))
3,练习2.9
我们先定义一下两倍区间宽度:
(define (width x)
(/ (- (upper-bound x) (lower-bound x)) 2.0))
对于区间加减法,我们要证明的是“区间和差的宽带等于宽带之和差”,我们下面以“差”为列,简单证明下,其中Lx表示区间x的下界,Ux表示区间x的上界,Wx表示区间x的宽度的两倍(之所以要两倍,是为了下面的证明书写起来方便,每个表达式都除以2写起来太繁琐了):
(width ( sub-interval x y))
=> (w (make-interval (- Lx Ly) (-Ux Uy)))
=> 由 (width x)的定义可知,其等于上界减去下界,而上面表达式中(make-interval (- Lx Ly) (-Ux Uy))的上界为(-Ux Uy) 下界为 (- Lx Ly),所以
=> (- (- Ux Uy) (- Lx Ly)))
=> 为了方便理解,将上面的表达式写成中缀的形式
=> ( Ux - Uy ) - (Lx - Ly)
=> Ux - Uy -Lx + Ly
=> (Ux - Lx) - ( Uy - Ly)
=>根据Width的定义,所以
=> Wx - Wy
所以“差的宽度,等于宽度之差”,求和同理。
乘除就不证明了,举个很简单的例子x=(2,4) y=(4,6),他们的积的宽度为8,而宽度之积为1.
4,练习2.10
非常简单,因为 y 的上下界要做分母,所以判断 其 是否为0:
(define (div-interval x y)
(if (or (= 0 (upper-bound y)) (= 0 (lower-bound y)))
(display "division by zero")
(mul-interval x
(make-interval (/ 1.0 (upper-bound y))
(/ 1.0 (lower-bound y))))))
5,练习2.11
Ben 这句神秘的话可真让程序变得无比晦涩啊:
(define (mul-interval x y)
(let ((a (lower-bound x))
(b (upper-bound x))
(c (lower-bound y))
(d (upper-bound y)))
(cond ((< b 0)
(cond ((< d 0)
(make-interval (* b d) (* a c)))
((< c 0)
(make-interval (* a d) (* a c)))
(else
(make-interval (* a d) (* b c)))))
((< a 0)
(cond ((< d 0)
(make-interval (* b c) (* a c)))
((< c 0)
(let ((p1 (* a c))
(p2 (* a d))
(p3 (* b c))
(p4 (* b d)))
(make-interval (min p1 p2 p3 p4)
(max p1 p2 p3 p4))))
(else
(make-interval (* a d) (* b d)))))
(else
(cond ((< d 0)
(make-interval (* b c) (* a d)))
((< c 0)
(make-interval (* b c) (* b d)))
(else
(make-interval (* a c) (* b d))))))))
6, 练习2.12
(define (percent c p)
(* p (/ c 100.0)))
(define (make-center-percent c p)
(let ((a (percent c p)))
(make-interval (- c a) (+ c a))))
7,练习2.13
首先,我们假设 x 的误差为 deltaX,那么 x 值的变化范围为 (x ± deltaX),为了表示方便,我们用 dx 来代表 ± deltaX,那么x的值的变化范围是(x+dx),另外 x 的百分误差值就应该为 (dx / x ) * 100%
然后,我们看两个具有误差的数 x 与 y 相乘:
( x + dx) * ( y + dy )
=> xy + x * dy + y * dx + dx * dy
由于dx与dy很小,所以 dx*dy趋近于0,我们可以将其省略,上式变成:
=> xy + x * dy + y * dx
不难理解,上式中的( x * dy + y * dx ) 是 xy 的误差,也就是说 xy 的变化范围是 xy + ( x * dy + y * dx)
那么 xy 的百分误差 (( x * dy + y * dx)/ xy ) * 100%, 也就是 ( dy/y + dx/x ) * 100%
8,练习2.14
两种方法在数学上是对等的,但计算机的实际计算结果是不同的,代码如下:
(define (make-interval a b) (cons a b))
(define (lower-bound x)
(car x))
(define (upper-bound x)
(cdr x))
(define (add-interval x y)
(make-interval (+ (lower-bound x) (lower-bound y))
(+ (upper-bound x) (upper-bound y))))
(define (mul-interval x y)
(let ((p1 (* (lower-bound x) (lower-bound y)))
(p2 (* (lower-bound x) (upper-bound y)))
(p3 (* (upper-bound x) (lower-bound y)))
(p4 (* (upper-bound x) (upper-bound y))))
(make-interval (min p1 p2 p3 p4)
(max p1 p2 p3 p4))))
(define (div-interval x y)
(mul-interval x
(make-interval (/ 1.0 (upper-bound y))
(/ 1.0 (lower-bound y)))))
(define (par1 r1 r2)
(div-interval (mul-interval r1 r2)
(add-interval r1 r2)))
(define (par2 r1 r2)
(let ((one (make-interval 1 1)))
(div-interval one
(add-interval (div-interval one r1)
(div-interval one r2)))))
(define (percent c p)
(* p (/ c 100.0)))
(define (make-center-percent c p)
(let ((a (percent c p)))
(make-interval (- c a) (+ c a))))
(define (center i)
(/ (+ (lower-bound i) (upper-bound i)) 2))
(define a (make-center-percent 2 5))
(define b (make-center-percent 3 6))
(center (par1 a b))
(center (par2 a b))
两个中心点计算下来的结果分别是:1.2148016178736518 和 1.1999711093990755
的确存在这样的差异,比如说 (1/3)*3 在数学上是等于1的,但在实际计算过程中,比如我们保留小数点后两位的精度,那么 1/3 等于 0.33 , 再乘以3,最后结果是0.99
9,练习2.15
感觉Eva Lu Ator说得有道理哈,比如数 a 在区间 (2, 3)之间,其误差为 ±0.5 , 而 a^a 则在 (4,9)之间,误差值为 ±2.5