SICP 第一章 1.1.7-1.2.1 学习

练习 1.6
当这样写的时候会内存溢出,原因是无限的递归调用,那是怎么造成递归的呢。原因在于,你将if else定义为一个过程,然后把需要递归的函数当作参数传递给这个过程,new-if的过程定义如下所示:

(define (new-if predicate then-clause else-clause)
  (cond (predicate then-clause)
        (else else-clause)))

可以简单的看成是 new-if( x ,y ,z)
对他的调用如下

(new-if (good-enough? guess x)
          guess
          (sqrt-iter (improve guess x)
                     x)))
可以简单的看成是 new-if(ex,ex,ex)
那么scheme运行的时候会先将参数表达式求值,然后才跳转到具体的过程体中去,假如每个ex都计算完了,每个ex的值假设是 x ,y,z 那么就执行类似如下的过程体:
(cond (x y)
        (else z)))
这是一般的执行过程。
但是在我们这个new-if的第三个参数中是一个递归的函数,这样只要参数是表达式的形式就会一直去解析,那么sqrt-iter就把自己当作参数一直在解析没有终止条件,但是有的人会说终止条件是good-enough?返回true(#t),在某些情况他可能是终止条件,但他属于过程的参数(或者说是函数的参数),那么他就不能算是终止条件,他的真假并不影响解释器继续去解析其他的参数表达式。
所以通过这个例子,我们也可以知道在过程的参数定义中最好不要让参数是被递归调用的过程表达式。

练习 1.7
假设我们的精度设置的是0.001,当我们对0.000000001计算他的平方根时,除法和乘法得出的结果的精准度是以他小数点后N位来决定的,数越小,除法和乘法的精度就依赖于系统对小数运算的支持程度了,在我们没有设置0.001作为比较差值时,这个差值的差异都是以小数点后第M位来决定的,位数越多就表明他们的相近程度越高,也就越接近真实的值,当我们以0.001来限定这个差异的时候,这个差异的范围被扩大了相对于0.000000001这样的比较参数,在很大的一个位范围来比较他们的差异,而不是说更加细的位比较,但是当我把精度设置为0.000000000000001的时候,他的计算结果就比较接近真实值。所以在对小数求平方根的时候需要把精度调整的尽量比小数本身小好几个数量级。

对于比较大的整数求平方跟,比如说是10的10次方,因为可能程序并不直接支持这么大的数的存储就会截取从而丢失精度,因此不是很适合,而且我们的精度选取的0.001.大数之间的差异用0.001来说就太苛刻了,其实可以设置为1,要不计算的时间偏长。

给出新的good-enough?过程定义如下
(define (good-enough? guess x )
  (< (/ (abs( - (improve guess x) guess)) guess ) 0.000001))

然后旧的good-enough?过程定义如下
(define (good-enough? guess x)
  (< (abs (- (square guess) x)) 0.000001))

然后开始测试,分别用新的,旧的,程序自己实现的sqrt来检测
> (sqrt 0.0000001)        系统自带的
0.00031622776601683794
> (sqrta 0.0000001)       旧的实现
0.0010104595507340792
> (sqrt2 0.0000001)       新的实现
0.00031622776664863746
看来对小数还是很有效果的,系统自带的精度可能要更加高些

对大数开始测试
> (sqrt 999999999999999)   系统自带的
31622776.601683777
> (sqrta 999999999999999)  旧的实现
31622776.601683777
> (sqrt2 999999999999999)  新的实现
31635794.32093877
对大数反而效果变差了,看来对于大数是不能用这样的检测的,因为除法中底数相对太大造成的商非常小可能丢失精度,比较就会失真。

练习 1.8
;求某个数的立方
(define (cube x)(* x (* x x)))

;求某个数的平方
(define (square x) (* x x))

;求两个数之和的三分之一
(define (third x y)(/ (+ x y) 3))

;求某个数的2倍,不用乘法因为乘法在系统中使用加法实现的
(define (twice x)( + x x))

;定义改进函数
(define (improve y x)
  (third (twice y) (/ x (square y))))

;定义终止判断函数
(define (good-enough? y x)
  (< (abs (- (cube y) x)) 0.001))

;定义求立方根的实现函数
(define (cubeRoot-iter y x)
  (if (good-enough? y x )
      y
      (cubeRoot-iter (improve y x)
                 x)))

;定义函数用来包装对其他函数的调用
(define (cubeRoot x)
  (cubeRoot-iter 1.0 x))

练习 1.9
第一个过程:
(+ 4 5)
(+ 3 5)
(。。。。
第二个过程:
(+ 4 5)
(+ 3 6)
不是迭代也不是递归

练习 1.10
(A 1 10)=> 2 的10次 1024
(A 2 4 )=> 4 的 8次 65536
(A 3 3)=>  4 的 8次 65536

过程F x取值为0 则 =>2n 所有的偶数
过程G x取值为1 则会走else => (A 1 n)=2的(A 1 n-1)次        
过程H x取值为2 则会走else => (A 2 n)=2的(A 2 n-1)次 
其中(A n 0)=0

你可能感兴趣的:(F#,Scheme)