SICP练习2.21-2.22

[code lang=”lisp”]
#lang racket
;;;(square-list (list 1 2 3 4))
;;;'( 1 2 3 16)

;;;Racket not support nil
(define nil ‘())
;;;the map define have given
(define (map proc items)
(if (null? items)
nil
(cons (proc (car items))
(map proc (cdr items)))))
(define (square x)(* x x))
;;;2.21
(define (square-list items)
(if (null? items)
nil
(cons (square (car items))
(square-list (cdr items)))))
(define (square-list2 items)
(map (lambda (x) (square x)) items))
;;; 2.22
;;;刚开始的定义
;;;(cons (square (car things) answer))先被处理的元素会被放到后面
;;;后来的定义的问题是cons 的第一个参数是list 第二个参数却是整数
;;;会得到一个比较奇怪的结果,比如
;;;> (square-list (list 1 2 3 4 5))
;;;(((((() . 1) . 4) . 9) . 16) . 25)
;;;正确的定义是
(define (square-list3 items)
(define (iter things answer)
(if (null? things)
answer
(iter (cdr things)
(append answer
(list (square (car things)))))))
(iter items null))
[/code]

SICP练习2.13

直接翻译一下其他人的答案好了,我堕落了,原文http://community.schemewiki.org/?sicp-ex-2.13

先不管scheme ,我们先用数学推导一下这个所谓的简单公式:

先假设Ca 是区间a的中间值,Ta是a的百分误差值

a = [Ca*(1-0.5*Ta),Ca*(1+0.5*Ta)]

同上

b = [Cb*(1-0.5*Tb),Cb*(1+0.5*Tb)]

如果所有区间值为正,a*b 的值是

a*b = [Ca*Cb*(1 - 0.5*(Ta + Tb) + 0.25*Ta*Tb),
         Ca*Cb*(1 + 0.5*(Ta + Tb) + 0.25*Ta*Tb)]
 因为Ta*Tb 是一个很小的值,所以可被忽略。所以误差很小的区间的乘积的误差可以看着是乘积双方的误差的和
下面用代码验证下:

[code lang=”lisp”]
;;;之前的一些定义
(define (make-interval a b) (cons a b))
(define (upper-bound interval) (max (car interval) (cdr interval)))
(define (lower-bound interval) (min (car interval) (cdr interval)))
(define (center i) (/ (+ (upper-bound i) (lower-bound i)) 2))

;;;误差百分比是在0和100之间
;;;按照之前数学推导的来定义
(define (make-interval-center-percent c pct)
(let ((width (* c (/ pct 100.0))))
(make-interval (- c width) (+ c width))))
;;;之前的老方法来定义
(define (percent-tolerance i)
(let ((center (/ (+ (upper-bound i) (lower-bound i)) 2.0))
(width (/ (- (upper-bound i) (lower-bound i)) 2.0)))
(* (/ width center) 100)))

(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 i (make-interval-center-percent 10 0.5))
(define j (make-interval-center-percent 10 0.4))
(percent-tolerance (mul-interval i j))

;;; 得到的值 0.89998, 很接近 (0.5 + 0.4).
[/code]

SICP练习2.10

如果一个区间upper lower 乘积小于等于0,说明是跨过0的区间
[sourcecode]
(define (div-interval x y)
(if (>= 0 (* (lower-bound y) (upper-bound y)))
(error "Division error (interval spans 0)" y)
(mul-interval x
(make-interval (/ 1.0 (upper-bound y))
(/ 1.0 (lower-bound y))))))
[/sourcecode]

SICP练习2.9

假设有两个区间a,b

a的宽度 width(a) = (aH-aL)/2  //H=hight=upper-bound

b的匡杜 width(b) = (bH-bL)/2


两者的和:a+b = ( (aH+bH),(aL+bL))

和的宽度

width(a+b)

= ((aH+bH)-(aL+bL))/2

=((aH-aL) + (bH-bL))/2

=(aH-aL)/2 +(bH-bL)/2

=width(a) + width(b)


两者的差 a-b = ((aL-bH),(aH-bL))

差的宽度

width(a-b)

= ( (aH-bL) -(aL-bH))/2

=((aH-aL) + (bH-bL))/2

=width(a)+width(b)


举例说明乘除例外:

这里说明一下乘法,如果说乘的宽度也适合乘法双方的宽度是函数关系,那么只要乘法双方的宽度不变,积的宽度也应该是不变的,但是事实并非如此

 

[0, 10] * [0, 2] = [0, 20]   (width = 10)
[-5, 5] * [0, 2] = [0, 10]   (width = 5)

 

虽然上面两个乘式双方的宽度是相同的,但是得出的积的宽度却是不同的,所以乘法的宽度和乘式双方的宽度的关系和加减是不同的。

SICP练习2.6

参考链接

http://www.billthelizard.com/2010/10/sicp-26-church-numerals.html

http://community.schemewiki.org/?sicp-ex-2.6

[sourcecode]
(define one
(lambda (f) (lambda (x) (f x))))

(define two
(lambda (f) (lambda (x) (f (f x)))))

(define (add a b)
(lambda (f)
(lambda (x)
((a f) ((b f) x)))))
[/sourcecode]

题目中说不让使用zero ,add-1 是指在最终的定义中不出现这两个过程的名字,在推导的过程中还是要用的