SICP 习题 (1.36)解题总结

SICP 习题 1.36 要求我们修改fixed-point函数,使它能够打印出计算中产生的近似值序列,使用练习1.22展示的newline和display方法。而后通过找出变换x => log (1000)/log(x)的不动点的方式确定x^x=1000的一个根(书中还提示你使用Scheme的基本过程log,用于计算自然对数值)。然后比较一下使用平均阻尼和不用平均阻尼的计算步数。要注意的是不能使用1作为初始猜测去启动fixed-point,因为log(1)=0,会导致0除数错误。

从题目来看,第一步比较简单,就是加多一些输出而已,这个我们程序员在行,平时调试就经常玩这一手。第二步求x^x=1000的根问题也不是太大,前提是你完成了习题1.35,最好是看完我的1.35题解题总结。第三步是比较使用平均阻尼和不使用平均阻尼的计算步数,就是做两次调用,一次使用平均阻尼,一次不使用,然后比较计算步数,计算步数这一块因为有第一步的输出命令变得比较简单,就是在控制台数一数就好了,对于平均阻尼,理解了习题1.35后也是比较简单。

总结而言,习题1.36是比较简单那种,主要是加深你对函数不动点和平均阻尼的理解。

开始吧,第一步就是修改fixed-point函数,使它能够打印出计算中产生的近似值序列。

因为fixed-point 主要是递归调用try函数产生不断逼近的近似值,所以我们只需要在try函数中将guess值打印出来就好了。

我在try函数里加了下面两句:

 (newline)
    (display (+ 0.0 guess))

最后结果是这样的:

(define tolerance 0.00001)

(define (fixed-point f first-guess)
  (define (close-enough? v1 v2)
    (< (abs (- v1 v2 )) tolerance))
  (define (try guess)
    (newline)
    (display (+ 0.0 guess))
    (let (( next (f guess)))
      (if (close-enough? guess next)
	  (+ 0.0 next)
	  (try next))))
  (try first-guess))

修改完以后可以用习题1.35中求黄金分割率的语句进行测试,就是:

(fixed-point (lambda (x) (+ 1 (/ 1 x))) 1)

测试结果如下,成功输出所有猜测值:

1.
2.
1.5
1.6666666666666667
1.6
1.625
1.6153846153846154
1.619047619047619
1.6176470588235294
1.6181818181818182
1.6179775280898876
1.6180555555555556
1.6180257510729614
1.6180371352785146
;Value: 1.618032786885246

我之所以在display输出的时候加一个(+ 0.0 guess),是想让Scheme输出一个小数值,不加这个直接输出guess的话会显示一个分数形式。

接着就是第二步,寻找变换x => log (1000)/log(x)的不动点,先不使用平均阻尼,直接使用变换:

调用过程是:

(fixed-point (lambda (x) (/ (log 1000) (log x))) 2)

从2开始猜,就像题目提示的,不能用1开始猜。

运算结果如下,结果比较长,慢慢看:

1 ]=> (fixed-point (lambda (x) (/ (log 1000) (log x))) 2)

2.
9.965784284662087
3.004472209841214
6.279195757507157
3.759850702401539
5.215843784925895
4.182207192401397
4.8277650983445906
4.387593384662677
4.671250085763899
4.481403616895052
4.6053657460929
4.5230849678718865
4.577114682047341
4.541382480151454
4.564903245230833
4.549372679303342
4.559606491913287
4.552853875788271
4.557305529748263
4.554369064436181
4.556305311532999
4.555028263573554
4.555870396702851
4.555315001192079
4.5556812635433275
4.555439715736846
4.555599009998291
4.555493957531389
4.555563237292884
4.555517548417651
4.555547679306398
4.555527808516254
4.555540912917957
;Value: 4.555532270803653

然后再来一个使用平均阻尼的,调用过程如下:

 (fixed-point (lambda (x) (/ (+ (/ (log 1000) (log x)) x) 2)) 2)

就是把变换变为 x => (x + log (1000)/log(x))/2

运算结果如下,可以发现输出很快逼近我们要的结果:

1 ]=>  (fixed-point (lambda (x) (/ (+ (/ (log 1000) (log x)) x) 2)) 2)

2.
5.9828921423310435
4.922168721308343
4.628224318195455
4.568346513136242
4.5577305909237005
4.555909809045131
4.555599411610624
4.5555465521473675
;Value: 4.555537551999825

解题结束!平均阻尼术真得很强!!

有兴趣的同学还可以尝试去证明为什么变换x => log (1000)/log(x)的不动点就是x^x=1000的根,对数运算哟!

SICP 习题 (1.36)解题总结,布布扣,bubuko.com

时间: 2024-10-06 06:23:06

SICP 习题 (1.36)解题总结的相关文章

SICP 习题 (2.30)解题总结 : Square-Tree

SICP 习题 2.30 要求我们完成一个叫square-tree的过程,其作用和之前的square过程差不多,square过程是针对简单列表的,将列表中的所有元素求平方,然后返回新的平方数列表.不过square不能对嵌套列表进行处理,如果列表中还包含列表的话会报错. 题目要求我们实现一个square-tree的过程,当输入的列表包含另一个列表时可以对嵌套的列表进行处理,生成所有列表元素的平方数. 这个和之前几道题差不多,都是对树状列表的遍历和处理.题目还要求我们用两种方式实现,一种使用map,

SICP 习题 (1.46)解题总结

SICP 习题 1.46 要求我们写一个过程iterative-improve,它以两个过程为参数,其中一个参数用来检测猜测是否足够好,另一个参数用来改进猜测.过程iterative-improve应该返回另一个过程,所返回的过程接收一个参数作为初始猜测,然后不断改进猜测直到结果足够好.题目还要求我们使用iterative-improve重写1.1.7的sqrt过程和1.3.3节的fixed-point过程. 因为涉及到高阶函数,所以整个题目理解起来有一点点费劲.不过这道题作为第一章的收官题确实

SICP 习题 (1.45)解题总结

SICP 习题 1.45是对前面很多关于不动点的习题的总结. 题目回顾了我们之前在1.3.3节使用的不动点寻找方法,当寻找y -> x/y 的不动点的时候,这个变换本身不收敛,需要做一次平均阻尼才可以. 对于y -> x/(y^2)这个变换也可以通过一次平均阻尼使它变得收敛. 不过一次平均阻尼对于四次方程是不够的,就是说,对y -> x/(y^3)这样的变换,一次平均阻尼不足以使它收敛,需要做两次平均阻尼才行. 题目遵从一直以来的抽象原则,要求我们去多做几次测试,找出 y -> x

SICP 习题 (2.10)解题总结: 区间除法中除于零的问题

SICP 习题 2.10 要求我们处理区间除法运算中除于零的问题. 题中讲到一个专业程序员Ben Bitdiddle看了Alyssa的工作后提出了除于零的问题,大家留意一下这个叫Ben的人,后面会不断出现这个人,只要是这个人提到的事情一般是对的,他的角色定位是个计算机牛人,不过是办公室经常能看到的那种牛人,后面还有更牛的. 对于区间运算的除于零的问题,处理起来也比较简单,只需要判断除数是不是为零,除数为零就报错.对于一个区间来讲,所谓为零就是这个区间横跨0,再直接一点讲就是起点是负数,终点是正数

SICP 习题 (2.22)解题总结: 迭代过程中的列表处理

SICP 习题 2.22是习题2.21的后续题目,题目中讲到叫Louis Reasoner的人想重写suqare-list过程,希望使用迭代计算过程,而不是递归计算过程,有关迭代计算过程和递归计算过程,如果你没什么印象了,请翻回习题1.9 的解题总结看看. 那个叫Louis Reasoner的人写的迭代版的suqre-list是这样的: (define (square-list-revert items) (define (iter things answer) (if (null? thing

SICP 习题 (2.2) 解题总结

SICP 习题 2.2要求我们使用这一节的数据抽象方法定义几何里"点"的概念,还要定义"线段"的概念,最后还要求我们定义midpoint-segment过程,这个过程根据参数中的线段进行计算,返回该线段的中点. 题目还给出了一个print-point过程,用于输出一个点,代码如下: (define (print-piont p) (newline) (display "(") (display (point-x p)) (display &quo

SICP 习题 (1.38)解题总结

SICP 习题1.38 紧跟着习题1.37的方向,要求我们用习题1.37中定义的cont-frac过程计算数学家欧拉大师在论文De Fractionibus Continuis 中提到的e-2的连分式.说实话,我不知道论文De Franctionibus Continuis讲的是什么,我甚至不知道论文的题目是什么意思.不过,这一切都不能阻止我这个数学盲去解答这道SICP习题. 仔细阅读题目,我们可以发现题目要求我们计算的是下面这样的无穷连分式: 其中N永远等于1, D等于1 ,  2 , 1 ,

SICP 习题 (1.39)解题总结

SICP 习题1.39沿着习题1.37, 1.38的方向继续前行,要求我们根据德国数学家J.H.Lambert的公式定义tan-cf过程,用于计算正切函数的近似值. J.H.Lambert的公式如下: 可以发现,这个和之前的无穷连分式是一样一样的,所不同的就是N是一个变量,不是固定数值. 不过这个已经难不倒我们啦,可以从公式中发现,除了第一个N是x,其它的N都是x平方, D对应的数值是1,3,5,就是所有奇数,以数字n为下标的话可以通过((n * 2)-1) 得到. 最后直接定义以下过程搞定:

SICP 习题 (1.37)解题总结

SICP 习题 1.37是一条很长的题目,主要讲的是无穷连分式.无穷连分式对我来说又是一个陌生的概念,于是又去百度了一番,发现无穷连分式也是一个很有意思的话题,涉及到无理数的表达.不过我建议大家还是暂时不要深入思考它的数学含义,一旦开始思考可能你又会跳进数学的深渊中不可自拔. 无穷连分式的形式如下: 就像书中说到的,作为无穷连分式的一个特殊例子,如果N和D都为1的话,f= 1/ φ, 这点可以结合我们之前对黄金分割率的计算证明,这里就不多说了,而且,如果你不能从数学上理解它也无所谓,不影响我们做