# SICP学习笔记 2.1.4 扩展练习：区间算术

练习2.7

;; 抽象对象"区间"有两个端点, 一个下界一个上界, 则直接有如下过程
(define (lower-bound x) (car x))
(define (upper-bound x) (cdr x))

练习2.8

(define (sub-interval x y)
(make-interval (- (lower-bound x) (upper-bound y))
(- (upper-bound x) (lower-bound y))))

练习2.9

;; 给定区间x=(a1, b1)、y=(a2, b2)
;; Wx=(a1+b1)/2、 Wy=(a2+b2)/2
;; 两个区间之和z=(a1+a2, b1+b2)
;; Wz=[(a1+a2) + (b1+b2)]/2
;;   =[a1+b1 + a2+b2]/2
;;   =Wx + Wy
;; 即两个区间之和的宽度为两个区间宽度之和
;; 同理得两个区间之差的宽度为两个区间宽度之差
;; 对于乘除
;; z=(a1*a2, b1*b2)
;; Wz=(a1*a2 + b1*b2)/2
;; 与Wy=(a2+b2)/2没有必然联系

练习2.10

;; 当出现跨越0的区间时,对其做除法,取其倒数,在0附近将分别得到负无穷和正无穷,因此需要规避此种情况
;; 在除法中添加对区间是否跨越0的判断
(define (div-interval x y)
(if (and (< (lower-bound y) 0) (> (upper-bound y) 0))
(display "error interval")
(mul-interval x
(make-interval (/ 1.0 (upper-bound y))
(/ 1.0 (lower-bound y))))))

练习2.11

;; 用+、-来表示一个区间上下界的正负情况,则对于两个区间来说有
;; ((+,+), (+,+))、((-,-), (-,-))
;; ((+,+), (-,-))、((-,-), (+,+))
;; ((+,+), (-,+))、((-,+), (+,+))
;; ((-,-), (-,+))、((-,+), (-,-))
;; ((-,+), (-,+))
;; 9种情况
;; 针对每种情况,因为已经确定了正负因此可以直接用两次乘法分别得到乘积区间的上下界
(define (new-mul-interval x y)
(let ((Lx (lower-bound x))
(Ux (upper-bound x))
(Ly (lower-bound y))
(Uy (upper-bound y)))
(cond ((and (< Ux 0) (< Uy 0))
(make-interval (* Ux Uy) (* Lx Ly)))
((and (> Lx 0) (> Ly 0))
(make-interval (* Lx Ly) (* Ux Uy)))
((and (> Lx 0) (< Uy 0))
(make-interval (* Ux Ly) (* Lx Uy)))
((and (< Ux 0) (> Ly 0))
(make-interval (* Lx Uy) (* Ux Ly)))
((and (> Lx 0) (< Ly 0) (> Uy 0))
(make-interval (* Ux Ly) (* Ux Uy)))
((and (> Ly 0) (< Lx 0) (> Ux 0))
(make-interval (* Uy Lx) (* Uy Ux)))
((and (< Ux 0) (< Ly 0) (> Uy 0))
(make-interval (* Lx Uy) (* Ux Ly)))
((and (< Uy 0) (< Lx 0) (> ux 0))
(make-interval (* Ly Ux) (* Uy Lx)))
((and (< Lx 0) (> Ux 0) (< Ly 0) (> Uy 0))
(make-interval (min (* Lx Uy) (* Ly Ux))
(max (* Lx Ly) (* Ux Uy)))))))

(define (test-mul a1 b1 a2 b2)
(let ((x (make-interval a1 b1))
(y (make-interval a2 b2)))
(new-mul-interval x y)))

1 ]=> (test-mul 1 2 2 3)
;Value 13: (2 . 6)

1 ]=> (test-mul 1 2 -3 -2)
;Value 16: (-6 . -2)

1 ]=> (test-mul 1 2 -3 2)
;Value 17: (-6 . 4)

1 ]=> (test-mul -2 1 -3 2)
;Value 18: (-4 . 6)

练习2.12

(define (persent c p)
(* p (/ c 100.0)))
(define (make-center-percent c p)
(let ((P (persent c p)))
(make-interval (- c P) (+ c P))))

练习2.13

;; 设区间X的误差为Px, 区间Y的误差为Py, 则有
;; (X±Px)、(Y±Py)
;; 设±Px=Dx、±Py=Dy, 则有
;; (X+Dx)*(Y+Dy)
;; =X*Y + X*Dy + Y*Dx + Dx*Dy
;; 在误差为很小的百分数时, Dx*Dy=0, 则有
;; (X+Dx)*(Y+Dy) = X*Y + X*Dy + Y*Dx
;; 即区间X、Y乘积的误差为X*Dy + Y*Dx
;; 则其百分数误差值为
;; [(X*Dy + Y*Dx)/(X*Y)]*100%
;; = (Dx/X + Dy/Y)*100%
;; 即(±Px/X + ±Py/Y)*100%

练习2.14

1 ]=> (div-interval (make-interval 4 5) (make-interval 4 5))
;Value : (.8 . 1.25)

1 ]=> (div-interval (make-interval 400 401) (make-interval 400 401))
;Value : (.997506234413965 . 1.0025)

1 ]=> (div-interval (make-interval 4 5) (make-interval 5 8))
;Value : (.5 . 1.)

1 ]=> (div-interval (make-interval 400 401) (make-interval 800 801))
;Value : (.4993757802746567 . .50125)

1 ]=> (par1 (make-center-percent 2 10) (make-center-percent 3 10))
;Value : (.8836363636363637 . 1.6133333333333333)

1 ]=> (par2 (make-center-percent 2 10) (make-center-percent 3 10))
;Value : (1.08 . 1.32)

;; par1和par2在数学表达式上来讲是对等的, 但是因为在对具体数字的计算过程中会有四舍五入和精度限制,因此会造成这样的两个不同的结果

练习2.15

;; 对于电阻串联公式	1 / (1/R1 + 1/R2)
;; 转换成par1的格式
1 / (1/R1 + 1/R2)
= 1 / (1/R1*(R2/R2) + 1/R2*(R1/R1))
= 1 / (R2/R1*R2 + R1/R1*R2)
= R1*R2/(R1+R2)
;; 即在此转换过程中假设了(R1/R1=1, R2/R2=1),但是在2.14中的测试
1 ]=> (div-interval (make-interval 4 5) (make-interval 4 5))
;Value : (.8 . 1.25)

1 ]=> (div-interval (make-interval 400 401) (make-interval 400 401))
;Value : (.997506234413965 . 1.0025)

;; 可知对于一个区间A, A/A的值并不为1, 因此使用par1进行计算将会扩大误差

练习2.16

;; 个人感觉应该不能, 因为等价的代数式必然经过一系列的变换,
;; 而在变换的过程中必然会对不准确的变量重复计算, 因此会放大误差, 越是复杂的变换可能得到的结果误差越大.
;; 但是如果能在事先对变换中的一些特殊计算进行特殊定义, 有可能会得到误差比较小的结果
;; 比如按照上面区间除法的过程, 对区间A/A的值并不为1, 如果对其特殊对待, 视其为(1, 1), 可能会好一些.