Scheme语言直译为汉语(十二)

2024-03-11 15:30

本文主要是介绍Scheme语言直译为汉语(十二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

序对cons还可以怎样实现

(define (cons x y)(define (dispatch m)(cond ((= m 0) x)((= m 1) y)(else (error "Argument not 0 or 1 -- CONS" m))))dispatch)
(define (car z) (z 0))
(define (cdr z) (z 1))

尝试把上述过程直译为汉语:

(定义 (序对 甲 乙)(定义 (寻值 序数)(情况符合 ((= 序数 0) 甲)((= 序数 1) 乙)(否则 (错误 "序数既不是0也不是1" 序数))))寻值)
(定义 (前项 丙) (丙 0))
(定义 (后项 丙) (丙 1))

应该特别注意这里的一个微妙之处:由(cons x y)返回的值是一个过程——也就是那个内部定义的过程dispatch,它有一个参数,并能根据参数是0还是1,分别返回x或者y。与此相对应,(car z) 被定义为将z应用于0,这样,如果z是由(cons x y)形成的过程,将z应用于0将会产生x,这样就证明了(car (cons x y)) 产生出x,正如我们所需要的。与此类似,(cdr (cons x y)) 将(cons x y)产生的过程应用于1而得到y。因此,序对的这一过程实现确实是–个合法的实现,如果只通过cons、car和cdr访问序对,我们将无法把这一实现与“真正的"数据结构区分开。

上面展示了序对的一种过程性表示,这并不意味着我们所用的语言就是这样做的(Scheme和一般的Lisp系统都直接实现序对,主要是为了效率),而是说它确实可以这样做。这一过程性表示虽然有些隐晦,但它确实是一种完全合适的表示序对的方式,因为它满足了序对需要满足的所有条件。这一实例也说明可以将过程作为对象去操作,因此就自动地为我们提供了一种表示复合数据的能力。这些东西现在看起来好像只是很好玩,但实际上,数据的过程性表示将在我们的程序设计宝库里扮演一种核心角色。有关的程序设计风格通常称为消息传递。在以后讨论模型和模拟时,我们将用它作为一种基本工具。

练习1
下面是序对的另一种过程性表示方式。请针对这一表示验证,对于任意的x和y,(car (cons x y))都将产生出x。

(define (cons x y)(lambda (m) (m x y)))
(define (car z)(z (lambda (p q) p)))

对应的cdr该如何定义?请利用代换模型验证上述表示确实可行。

尝试把题中过程直译为汉语:

(定义 (序对 甲 乙)(规定 (序) (序 甲 乙)))
(定义 (前项 丙)(丙 (规定 (戊 己) 戊)))

(car (cons 1 2))

的展开序列:

(car z)
(z (lambda (p q) p))
((cons x y) (lambda (p q) p))
((lambda (m) (m x y)) (lambda (p q) p))
((lambda (p q) p) x y)
x

尝试把上述过程直译为汉语:

(前项 丙)
(丙 (规定 (戊 己) 戊))
((序对 甲 乙) (规定 (戊 己) 戊))
((规定 (序) (序 甲 乙)) (规定 (戊 己) 戊))
((规定 (戊 己) 戊) 甲 乙)
甲

cdr:

(define (cdr z)(z (lambda (p q) q)))

尝试把上述过程直译为汉语:

(定义 (后项 丙)(丙 (规定 (戊 己) 己)))

练习2
请证明,如果将 a a a b b b的序对表示为乘积 2 a 3 b 2^a 3^b 2a3b对应的整数,我们就可以只用非负整数和算术运算表示序对。请给出对应的过程cons、car和cdr的定义。


我们先按题中意思找两个数试一下,比如12和31?两个数要组成序对<12,31>,那按题中意思,我们就要把它俩写成 2 12 ⋅ 3 31 2^{12}\cdot3^{31} 212331这样,我们发现由于2和3是两个互质数,那要获取前项car的话,就可以一直除2直至除净,每次除2加1,就能把12这个数弄出来;要获得31,则相应的可以一直除3,直至除净,每次除以3时加一就能把31这个数算出来。

(define (cons x y)(* (expt 2 x)(expt 3 y)))
(define (car z)(if (= 0 (remainder z 2))(+ 1 (car (/ z 2)))0))
(define (cdr z)(if (= 0 (remainder z 3))(+ 1 (cdr (/ z 3)))0))

尝试把上述过程直译为汉语:

(定义 (序对 甲 乙)(* (幂 2 甲)(幂 3 乙)))
(定义 (前项 丙)(如果 (= 0 (取余数 丙 2))(+ 1 (前项 (/ 丙 2)))0))
(定义 (后项 丙)(如果 (= 0 (取余数 丙 3))(+ 1 (后项 (/ 丙 3)))0))

练习3
如果觉得将序对表示为过程还不够劲儿,那么请考虑,在一个可以对过程做各种操作的语言里,我们完全可以没有数(至少在只考虑非负整数的情况下),可以将0和加一操作实现为:

(define zero (lambda (f) (lambda (x) x)))(define (add-1 n)(lambda (f) (lambda (x) (f ((n f) x)))))

这一表示形式称为Church计数,名字来源于其发明人数理逻辑学家Alonzo Church (丘奇), λ \lambda λ演算也是他发明的。

请直接定义one和two (不用zero和add-1) (提示:利用代换去求值(add-1 zero))。请给出加法过程+的一个直接定义(不要通过反复应用add-1)。


说实话,看着题中的这俩定义,盯了半天看不出这是怎么定义的0和加一运算。不过按照题目的提示,可以先不管它为啥这样就定义了零和加一,利用代换求值(add-1 zero),一步步代换也能在依然处于懵逼状态下给出one的定义:

;(define one (add-1 zero))
;(define one
;    (lambda (f) (lambda (x) (f ((zero f) x)))))
;(define one
;    (lambda (f) (lambda (x) (f ((
;        (lambda (f) (lambda (x) x)) f) x)))))
;(define one
;    (lambda (f) (lambda (x) (f ((lambda (x) x) x)))))
(define one(lambda (f) (lambda (x) (f x))))

尝试把上述过程直译为汉语:

;(定义 一 (加一 零))
;(定义 一
;    (规定 (道) (规定 (元) (道 ((零 道) 元)))))
;(定义 一
;    (规定 (道) (规定 (元) (道 ((
;        (规定 (道) (规定 (元) 元)) 道) 元)))))
;(定义 一
;    (规定 (道) (规定 (元) (道 ((规定 (元) 元) 元)))))
(定义 一(规定 (道) (规定 (元) (道 元))))

接下来,定义two也就是一加一呗,唉,继续代换:

;(define two
;    (add-1 one))
;(define two
;    (lambda (f) (lambda (x) (f ((one f) x)))))
;(define two
;    (lambda (f) (lambda (x) (f ((
;        (lambda (f) (lambda (x) (f x))) f) x)))))
;(define two
;    (lambda (f) (lambda (x) (f ((lambda (x) (f x)) x)))))
;(define two(lambda (f) (lambda (x) (f (f x)))))

尝试把上述过程直译为汉语:

;(定义 二
;    (加一 一))
;(定义 二
;    (规定 (道) (规定 (元) (道 ((一 道) 元)))))
;(定义 二
;    (规定 (道) (规定 (元) (道 ((
;        (规定 (道) (规定 (元) (道 元))) 道) 元)))))
;(定义 二
;    (规定 (道) (规定 (元) (道 ((规定 (元) (道 元)) 元)))))
(定义 二(规定 (道) (规定 (元) (道 (道 元)))))

用代换法定义一下add-2试试,也就是(add-1(add-1 n))

;(define (add-2 n)
;    (add-1 (add-1 n)))
;(define (add-2 n)
;    (add-1 (lambda (f) (lambda (x) (f ((n f) x))))))
;(define (add-2 n)
;    (lambda (f) (lambda (x) (f (((lambda (f) (lambda (x) (f ((n f) x)))) f) x)))))
;(define (add-2 n)
;    (lambda (f) (lambda (x) (f ((lambda (x) (f ((n f) x))) x)))))
;(define (add-2 n)
;    (lambda (f) (lambda (x) (f (f ((n f) x))))))

推到这里之后,我查答案,人家说还能往后推出这样一步:

(define (add-2 n)(lambda (f) (lambda (x) ((two f) ((n f) x)))))

但我说真的,实在看不出这一步怎么来的,我怀疑是不是需要对邱奇计数的本质真正理解之后才能写出这一步?不知道。。。

但若有了上面这步后,我们可以套用数学归纳法的方法,假定add-m-1为:

(define (add-2 n)(lambda (f) (lambda (x) ((m-1 f) ((n f) x)))))

再接下来,继续用代换的方法来求add-m,add-m 也就是(add-1 (add-m-1 n))喽:

; (define (add-m n)
;   (add-1 (add-m-1 n)))
; (define (add-m n)
;   (add-1 (lambda (f) (lambda (x) ((m-1 f) ((n f) x))))))
; (define (add-m n)
;   (lambda (f) (lambda (x) (f (((lambda (f) (lambda (x) ((m-1 f) ((n f) x)))) f) x)))))
; (define (add-m n)
;   (lambda (f) (lambda (x) (f ((lambda (x) ((m-1 f) ((n f) x))) x)))))
; (define (add-m n)
;   (lambda (f) (lambda (x) (f ((m-1 f) ((n f) x))))))
; (define (add-m n)
;   (lambda (f) (lambda (x) ((m f) ((n f) x)))))

因而+的定义也就是:

(define (+ m n)(lambda (f) (lambda (x) ((m f) ((n f) x)))))

后来逛知乎,感觉这位网友对邱奇计数对解释还挺有意思的:
在这里插入图片描述
扩展练习:区间算数

AlyssaP.Hacker正在设计一个帮助人们求解工程问题的系统。她希望这个系统提供的一个特征是能够去操作不准确的量(例如物理设备的测量参数),这种量具有已知的精度,所以,在对这种近似量进行计算时,得到的结果也应该是已知精度的数值。

电子工程师将会用Alyssa的系统去计算一些电子量。有时他们必须使用下面公式,从两个电阻R1和R2计算出并联等价电阻Rp的值:
R p = 1 1 / R 1 + 1 / R 2 R_{p}= \frac{1}{1/R_{1} + 1/{R_2}} Rp=1/R1+1/R21

此时所知的电阻值通常是由电阻生产厂商给出的带误差保证的值,例如你可能买到一支标明“6.8欧姆误差10%”的电阻,这时我们就只能确定,这支电阻的阻值在6.8 - 0.68 =6.12和6.8 + 0.68 =7.48欧姆之间。这样,如果将一支6.8欧姆误差10%的电阻与另一支4.7欧姆误差5%的电阻并联,这一组合的电阻值可以在大约2.58欧姆(如果两支电阻都有最小值)和2.97欧姆(如果两支电阻都是最大值)之间。

Alyssa的想法是实现一套“区间算术”,即作为可以用于组合“区间”(表示某种不准确量的可能值的对象)的一组算术运算。两个区间的加、减、乘、除的结果仍是一个区间,表示的是计算结果的范围。

Alyssa假设有一种称为“区间”的抽象对象,这种对象有两个端点,一个下界和一个上界。她还假定,给了一个区间的两个端点,就可以用数据构造函数make-interval构造出相应的区间来。Alyssa首先写出了一个做区间加法的过程,她推理说,和的最小值应该是两个区间的下界之和,其最大值应该是两个区间的上界之和:

(define (add-interval x y)(make-interval (+ (lower-bound x) (lower-bound y))(+ (upper-bound x) (upper-bound y))))

尝试把上述过程直译为汉语:

(定义 (区间加法 被加区间 加区间)(创建区间 (+ (下界 被加区间) (下界 加区间))(+ (上界 加区间) (上界 被加区间))))

Alyssa还找出了这种界的乘积的最小和最大值,用它们做出了两个区间的乘积(min和max是求出任意多个参数中的最小值和最大值的基本过程)。

(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))))

尝试把上述过程直译为汉语:

(定义 (区间乘法 被乘区间 乘区间)(命 ((甲 (* (下界 被乘区间) (下界 乘区间)))(乙 (* (下界 被乘区间) (上界 乘区间)))(丙 (* (上界 被乘区间) (下界 乘区间)))(丁 (* (上界 被乘区间) (上界 乘区间))))(创建区间 (取最小值 甲 乙 丙 丁)(取最大值 甲 乙 丙 丁))))

为了做出两个区间的除法,Alyssa用第一个区间乘上第二个区间的倒数。请注意,倒数的两个界限分别是原来区间的上界的倒数和下界的倒数:

(define (div-interval x y)(mul-interval x(make-interval (/ 1.0 (upper-bound y))(/ 1.0 (lower-bound y)))))

尝试把上述过程直译为汉语:

(定义 (区间除法 被除区间 除区间)(区间乘法 被除区间(创建区间 (/ 1.0 (上界 除区间))(/ 1.0 (下界 除区间)))))

练习2.7
Alyssa的程序是不完整的,因为她还没有确定区间抽象的实现。这里是区间构造符的定义:

(define (make-interval a b) (cons a b))

尝试把上面这句直译为汉语:

(定义 (创建区间 始 终) (序对 始 终))

请定义选择符upper-bound和lower-bound,完成这一实现。

(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)))

尝试把上述过程直译为汉语:

(定义 (创建区间 始 终) (序对 始 终))(定义 (上界 区间)(取最大值 (前项 区间) (后项 区间)))(定义 (下界 区间)(取最小值 (前项 区间) (后项 区间)))

练习2.8
通过 类似于Alyssa的推理,说明两个区间的差应该怎样计算。请定义出相应的减法过程sub-interval。


我们需要模仿除法的处理,减法就是把减去区间的两个端点取相反数构造新区间与被减区间进行加法运算:

(define (make-interval a b) (cons a b))(define (upper-bound i)(max (car i) (cdr i)))(define (lower-bound i)(min (car i) (cdr i)))(define (add-interval x y)(make-interval (+ (lower-bound x) (lower-bound y))(+ (upper-bound x) (upper-bound y))))(define (inv-interval i)(make-interval (- (lower-bound i))(- (upper-bound i))))(define (sub-interval x y)(add-interval x (inv-interval y)))

尝试把上述过程直译为汉语:

(定义 (创建区间 始 终) (序对 始 终))(定义 (上界 区间)(取最大值 (前项 区间) (后项 区间)))(定义 (下界 区间)(取最小值 (前项 区间) (后项 区间)))(定义 (区间加法 被加区间 加区间)(创建区间 (+ (下界 被加区间) (下界 加区间))(+ (上界 被加区间) (上界 加区间))))(定义 (创建减区间 区间)(创建区间 (- (下界 区间))(- (上界 区间))))(定义 (区间减法 被减区间 减区间)(区间加法 被减区间 (创建减区间 减区间)))

练习2.9
区间的宽度就是其上界和下界之差的- -半。区间宽度是有关区间所描述的相应数值的非确定性的一种度量。对于某些算术运算,两个区间的组合结果的宽度就是参数区间的宽度的函数,而对其他运算,组合区间的宽度则不是参数区间宽度的函数。证明两个区间的和(与差)的宽度就是被加(或减)的区间的宽度的函数。举例说明,对于乘和除而言,情况并非如此。


说明
I I I 表示区间
u ( I ) u(I) u(I) 表示 I I I 的上界
l ( I ) l(I) l(I) 表示 I I I 的下界
w ( I ) w(I) w(I) 表示 I I I 的宽度
+ , − , × , / +, -, \times, / +,,×,/ 可用于区间
w ( I ) w(I) w(I) 的定义如下:

w ( I ) = u ( I ) − l ( I ) 2 w(I) = \frac{u(I) - l(I)}{2} w(I)=2u(I)l(I)
对于加法:

u ( I 1 + I 2 ) = u ( I 1 ) + u ( I 2 ) u(I_1 + I_2) = u(I_1) + u(I_2) u(I1+I2)=u(I1)+u(I2)
l ( I 1 + I 2 ) = l ( I 1 ) + l ( I 2 ) l(I_1 + I_2) = l(I_1) + l(I_2) l(I1+I2)=l(I1)+l(I2)
因此:

w ( I 1 + I 2 ) = u ( I 1 + I 2 ) − l ( I 1 + I 2 ) 2 = u ( I 1 ) − l ( I 1 ) + u ( I 2 ) − l ( I 2 ) 2 = w ( I 1 ) + w ( I 2 ) \begin{aligned} w(I_1 + I_2) &= \frac{u(I_1 + I_2) - l(I_1 + I_2)}{2} \\ &= \frac{u(I_1) - l(I_1) + u(I_2) - l(I_2)}{2} \\ &= w(I_1) + w(I_2) \end{aligned} w(I1+I2)=2u(I1+I2)l(I1+I2)=2u(I1)l(I1)+u(I2)l(I2)=w(I1)+w(I2)
对于减法:

w ( I 1 − I 2 ) = w ( I 1 + ( − I 2 ) ) = u ( I 1 + ( − I 2 ) ) − l ( I 1 + ( − I 2 ) ) 2 = u ( I 1 ) − l ( I 1 ) + u ( − I 2 ) − l ( − I 2 ) 2 = w ( I 1 ) + w ( I 2 ) \begin{aligned} w(I_1 - I_2) &= w(I_1 + (-I_2)) \\ &= \frac{u(I_1 + (-I_2)) - l(I_1 + (-I_2))}{2} \\ &= \frac{u(I_1) - l(I_1) + u(-I_2) - l(-I_2)}{2} \\ &= w(I_1) + w(I_2) \end{aligned} w(I1I2)=w(I1+I2))=2u(I1+(I2))l(I1+(I2))=2u(I1)l(I1)+u(I2)l(I2)=w(I1)+w(I2)
对于乘法,要证明不是被乘区间宽度的函数,只需证明被乘区间宽度确定时,乘积区间的宽度不定。

不妨取第一个区间为 [ 0 , 1 ] [0, 1] [0,1], 第二个区间分别为 [ 0 , 1 ] [0, 1] [0,1] [ 1 , 2 ] [1, 2] [1,2],此时,乘积区间的宽度分别为 0.5 0.5 0.5 1 1 1,因此,乘积区间的宽度不是被乘区间宽度的函数。

对于除法,证明过程与乘法类似。

练习2.10
Ben Bitdiddle是个专业程序员,他看了Alyssa工作后评论说,除以一个横跨0的区间的意义不清楚。请修改Alyssa的代码,检查这种情况并在出现这一情况时报错。

只需修改除法的实现,在其中加一行判断被除区间有没有跨0,如果有的话输出错误信息即可:

(define (div-interval x y)(if (and (> (upper-bound y) 0)(< (lower-bound y) 0))(error "Not support interval cross 0 -- Div-Interval")(mul-interval x(make-interval (/ 1.0 (upper-bound y))(/ 1.0 (lower-bound y))))))

尝试把上述过程直译为汉语:

(定义 (区间除法 被除区间 除区间)(如果 (&& (> (上界 除区间) 0)(< (下界 除区间) 0))(错误 "区间除法中除区间不能跨过0")(区间乘法 被除区间(创建区间 (/ 1.0 (上界 除区间))(/ 1.0 (下界 除区间))))))

练习2.11

在看了这些东西之后,Ben又说出了下面这段有些神秘的话:“通过监测区间的端点,有可能将mu1-interval分解为9种情况,每种情况中所需的乘法都不超过两次”。请根据Ben的建议重写这个过程。

(define (make-interval a b) (cons a b))(define (upper-bound i)(max (car i) (cdr i)))(define (lower-bound i)(min (car i) (cdr i)))(define (mul-interval x y)(let ((ux (upper-bound x))(lx (lower-bound x))(uy (upper-bound y))(ly (lower-bound y)))(if (<= ux 0)(cond ((<= uy 0)(make-interval (* ux uy) (* lx ly)))((>= ly 0)(make-interval (* lx uy) (* ux ly)))(else(make-interval (* lx uy) (* lx ly))))(if (>= lx 0)(cond ((<= uy 0)(make-interval (* ux ly) (* lx uy)))((>= ly 0)(make-interval (* lx ly) (* ux uy)))(else (make-interval (* ux ly) (* ux uy))))(if (and (< lx 0) (> ux 0))(cond ((<= uy 0)(make-interval (* ux ly) (* lx ly)))((>= ly 0)(make-interval (* lx uy) (* ux uy)))(else (make-interval (min (* lx uy) (* ux ly))(max (* lx ly) (* ux uy))))))))))(define (display-interval i)(newline)(display "(")(display (lower-bound i))(display ",")(display (upper-bound i))(display ")"))(define x (make-interval -1 -2))
(define y (make-interval -4 -3))
(display-interval (mul-interval x y))(exit)

尝试把上述过程直译为汉语:

(定义 (创建区间 始 终) (序对 始 终))(定义 (上界 区间)(取最大值 (前项 区间) (后项 区间)))(定义 (下界 区间)(取最小值 (前项 区间) (后项 区间)))(定义 (区间乘法 线区间 面区间)(命 ((线区间上界 (上界 线区间))(线区间下界 (下界 线区间))(面区间上界 (上界 面区间))(面区间下界 (下界 面区间)))(如果 (<= 线区间上界 0)(情况符合 ((<= 面区间上界 0)(创建区间 (* 线区间上界 面区间上界) (* 线区间下界 面区间下界)))((>= 面区间下界 0)(创建区间 (* 线区间下界 面区间上界) (* 线区间上界 面区间下界)))(否则(创建区间 (* 线区间下界 面区间上界) (* 线区间下界 面区间下界))))(如果 (>= 线区间下界 0)(情况符合 ((<= 面区间上界 0)(创建区间 (* 线区间上界 面区间下界) (* 线区间下界 面区间上界)))((>= 面区间下界 0)(创建区间 (* 线区间下界 面区间下界) (* 线区间上界 面区间上界)))(否则 (创建区间 (* 线区间上界 面区间下界) (* 线区间上界 面区间上界))))(如果 (&& (< 线区间下界 0) (> 线区间上界 0))(情况符合 ((<= 面区间上界 0)(创建区间 (* 线区间上界 面区间下界) (* 线区间下界 面区间下界)))((>= 面区间下界 0)(创建区间 (* 线区间下界 面区间上界) (* 线区间上界 面区间上界)))(否则 (创建区间 (取最小值 (* 线区间下界 面区间上界) (* 线区间上界 面区间下界))(取最大值 (* 线区间下界 面区间下界) (* 线区间上界 面区间上界))))))))))(定义 (输出区间 区间)(换行)(显示 "(")(显示 (下界 区间))(显示 ",")(显示 (上界 区间))(显示 ")"))(定义 线区间 (创建区间 -1 -2))
(定义 面区间 (创建区间 -4 -3))
(输出区间 (区间乘法 线区间 面区间))(退出)

在排除了自己程序里的错误之后,Alyssa给一个可能用户演示自己的程序。那个用户却说她的程序解决的问题根本不对。他希望能够有一个程序,可以用于处理那种用一个中间值和一个附加误差的形式表示的数,也就是说,希望程序能处理 3.5 ± 0.15 3.5 \pm 0.15 3.5±0.15而不是[3.35,3.65]。Alyssa回到自己的办公桌来纠正这一问题,另外提供了一个构造符和一个选择符:

(define (make-center-width c w)(make-interval (- c w) (+ c w)))
(define (center i)(/ (+ (lower-bound i) (upper-bound i)) 2))
(define (width i)(/ (- (upper-bound i) (lower-bound i)) 2))
(定义 (构建误差区间 中间值 允许误差)(创建区间 (- 中间值 允许误差) (+ 中间值 允许误差)))
(定义 (中点 区间)(/ (+ (下界 区间) (上界 区间)) 2))
(定义 (半宽 区间)(/ (- (上界 区间) (下界 区间)) 2))

不幸的是,Alyssa的大部分用户是工程师,现实中的工程师经常遇到只有很小的不准确性的测量值,而且常常是以区间宽度对区间中点的比值作为度量值。他们通常用的是基于有关部件的参数的百分数描述的误差,就像前面描述电阻值的那种方式一样。

练习2.12
请定义一个构造函数make-center-percent,它以一个中心点和一个百分比为参数,产生出所需要的区间。你还需要定义选择函数percent,通过它可以得到给定区间的百分数误差,选择函数center与前面定义的一样。

(define (make-interval a b) (cons a b))(define (upper-bound i)(max (car i) (cdr i)))(define (lower-bound i)(min (car i) (cdr i)))(define (center i)(/ (+ (lower-bound i) (upper-bound i)) 2))(define (width i)(/ (- (upper-bound i) (lower-bound i)) 2))(define (make-center-percent c p)(let ((w (* c p)))(make-interval (- c w) (+ c w))))(define (percent i)(/ (width i) (center i)))

尝试把上述过程直译为汉语:

(定义 (创建区间 始 终) (序对 始 终))(定义 (上界 区间)(取最大值 (前项 区间) (后项 区间)))(定义 (下界 区间)(取最小值 (前项 区间) (后项 区间)))(定义 (中间值 区间)(/ (+ (下界 区间) (上界 区间)) 2))(定义 (半宽 区间)(/ (- (上界 区间) (下界 区间)) 2))(定义 (构建百分比误差率区间 中间值 误差率)(命 ((误差值 (* 中间值 误差率)))(创建区间 (- 中间值 误差值) (+ 中间值 误差值))))(定义 (百分数误差值 区间)(/ (半宽 区间) (中间值 区间)))

练习 2.13
请证明,在误差为很小的百分数的条件下,存在着一个简单公式,利用它可以从两个被乘区间的误差算出乘积的百分数误差值。你可以假定所有的数为正,以简化这一问题。


假设所有的数为正, c 1 , c 2 , w 1 , w 2 , p 1 , p 2 c1, c2, w1, w2, p1, p2 c1,c2,w1,w2,p1,p2分别为两个被乘区间的中点、宽度、百分比误差, l , u , w , c l, u, w, c l,u,w,c分别为乘积区间的下界、上界、宽度、中点,则

l = ( c 1 − w 1 ) ( c 2 − w 2 ) u = ( c 1 + w 1 ) ( c 2 + w 2 ) w = u − l 2 c = u + l 2 l = (c_{1} - w_{1})(c_{2} - w_{2})\\ u = (c_{1} + w_{1})(c_{2} + w_{2}) \\ w = \frac{u - l}{2} \\ c = \frac{u + l}{2} l=(c1w1)(c2w2)u=(c1+w1)(c2+w2)w=2ulc=2u+l

百分比误差:

p = w c = u − l u + l = c 1 w 2 + c 2 w 1 c 1 c 2 + w 1 w 2 = p 1 + p 2 p 1 p 2 + 1 ≈ p 1 + p 2 ( p 1 < < 1 , p 2 < < 1 ) \begin{aligned} p =& \frac{w}{c} \\ =& \frac{u-l}{u+l}\\ =& \frac{c_{1}w_{2} + c_{2}w_{1}}{c_{1}c_{2} + w_{1}w_{2}} \\ =& \frac {p_{1} + p_{2}}{p_{1}p_{2} + 1} \\ \approx & p_{1} + p_{2} (p_1 << 1, p_2 << 1) \end{aligned} p====cwu+lulc1c2+w1w2c1w2+c2w1p1p2+1p1+p2p1+p2(p1<<1,p2<<1)

(未完待续……)

参考文献:
[1] [美]Julie Sussman.计算机程序的构造和解释[M]. 裘宗燕译注.北京:机械工业出版社,1996.

这篇关于Scheme语言直译为汉语(十二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/798224

相关文章

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

MiniGPT-3D, 首个高效的3D点云大语言模型,仅需一张RTX3090显卡,训练一天时间,已开源

项目主页:https://tangyuan96.github.io/minigpt_3d_project_page/ 代码:https://github.com/TangYuan96/MiniGPT-3D 论文:https://arxiv.org/pdf/2405.01413 MiniGPT-3D在多个任务上取得了SoTA,被ACM MM2024接收,只拥有47.8M的可训练参数,在一张RTX

如何确定 Go 语言中 HTTP 连接池的最佳参数?

确定 Go 语言中 HTTP 连接池的最佳参数可以通过以下几种方式: 一、分析应用场景和需求 并发请求量: 确定应用程序在特定时间段内可能同时发起的 HTTP 请求数量。如果并发请求量很高,需要设置较大的连接池参数以满足需求。例如,对于一个高并发的 Web 服务,可能同时有数百个请求在处理,此时需要较大的连接池大小。可以通过压力测试工具模拟高并发场景,观察系统在不同并发请求下的性能表现,从而

C语言:柔性数组

数组定义 柔性数组 err int arr[0] = {0}; // ERROR 柔性数组 // 常见struct Test{int len;char arr[1024];} // 柔性数组struct Test{int len;char arr[0];}struct Test *t;t = malloc(sizeof(Test) + 11);strcpy(t->arr,

C语言指针入门 《C语言非常道》

C语言指针入门 《C语言非常道》 作为一个程序员,我接触 C 语言有十年了。有的朋友让我推荐 C 语言的参考书,我不敢乱推荐,尤其是国内作者写的书,往往七拼八凑,漏洞百出。 但是,李忠老师的《C语言非常道》值得一读。对了,李老师有个官网,网址是: 李忠老师官网 最棒的是,有配套的教学视频,可以试看。 试看点这里 接下来言归正传,讲解指针。以下内容很多都参考了李忠老师的《C语言非

C 语言基础之数组

文章目录 什么是数组数组变量的声明多维数组 什么是数组 数组,顾名思义,就是一组数。 假如班上有 30 个同学,让你编程统计每个人的分数,求最高分、最低分、平均分等。如果不知道数组,你只能这样写代码: int ZhangSan_score = 95;int LiSi_score = 90;......int LiuDong_score = 100;int Zhou

C 语言的基本数据类型

C 语言的基本数据类型 注:本文面向 C 语言初学者,如果你是熟手,那就不用看了。 有人问我,char、short、int、long、float、double 等这些关键字到底是什么意思,如果说他们是数据类型的话,那么为啥有这么多数据类型呢? 如果写了一句: int a; 那么执行的时候在内存中会有什么变化呢? 橡皮泥大家都玩过吧,一般你买橡皮泥的时候,店家会赠送一些模板。 上

linux中使用rust语言在不同进程之间通信

第一种:使用mmap映射相同文件 fn main() {let pid = std::process::id();println!(