SICP-《计算机程序的构造和解释》之习题分析与收获——练习1.29

前面给出了sum函数的定义:


(define (sum term a next b)
    (if (> a b)
        0
        (+ (term a)
           (sum term (next a) next b))))
//功能为求f(a)到f(b)的和。

这里我们要求的辛普森公式里的每一项(a)为两部分构成:乘法因子和y。所有我们要把他抽象为另一个函数:


(define (term k)
(* (factor k) (y k)))

这里的乘法因子是关于k奇数为4偶数为2,当k为0或n的时候就是1.则有:


(define (factor k)
(cond ((or(= k 0)(= k n)) 1)
  ((odd? k) 4)
  (else 2)))
 
根题yk=f(a+kh),直接写出来为:


(define (y k)
f((+ a (* k h))))
//这里的f使用的是最外层函数的参数函数


于是我们就可以利用sum函数和我们定义的函数解决右括号里的求和问题,这里发现还少了一个next:


(define (next a)
(+ a 1))

于是调用方式为: sum term 0 n 


于是我们开始构造外层函数--(我的顺序是不是有问题~):


(load "p38-sum.scm")//sum是题目给出的算法,前面有介绍
(define (simpson f a b n)   
//先嵌入函数
//顺序为先变量,再底层函数,再上层函数  (这里用的是现在流行语言的一些定义名称)
(define h (/ (- b a) n))
(define (factor k)
(cond ((or(= k 0)(= k n)) 1)
  ((odd? k) 4)
  (else 2)))
(define (y k)
f((+ a (* k h))))
(define (term k)
(* (factor k) (y k)))
(define (next a)
(+ a 1))
//以下为函数主体
(if (not (even? n))              //这里不用(odd? n)是为了保证它是一个偶数从而限制其他可能的输出情况
   (error "n can't be odd"))   //error放前面提示这是一个错误
(*(/ h 3)                       //分开放方便查看
(sum term 0 next n))))      //最后一个)对应第一个define前面的(

至此应该已经通过高阶函数抽象把这个辛普森这个式子用程序实现了。这个例子没有前面的递归那么思维逻辑有一定要求,但是它主要让我们练习深入了这种抽象过程的思维过程好比sum是一种求和的公共模式,这里就存在一种很实用的抽象,于是我们有了sum这个函数,而当我们使用这个函数模板时我们需要根据他的参数把自己的数据和过程抽象出来。刚开始题目提供了一个函数f,我就直接把这个f当做sun的term参数去套,然后发现他前面还有乘法因子,然后我试着用4f(a+kh)去给参数term赋值,但这个参数只是一个过程,所以,怎么办。然后我就想到了把4f(a+kh)这种复杂的东西抽象为F(k),于是一切都很好控制了。也许,现代的编程语言也是把这一切过程都抽象为函数吧,所谓的黑箱科学吧。

1,过程作为返回值 在1.3中我们明白了高阶函数之后,“用一个过程作为另外一个过程的返回值”则是稀松平常的事情了,比如下面的代码: (define (f x) (+ x 1)) (define (g) f) ((g) 2) 函数g没有参数,其返回值为函数f,所以((g) 2)就运算结果就是(f 2),最后运算结果为3。 上面是用一个已命名的函数作为返回结果的,相应的,也可以将一个“匿名过程”作为结果返回,这里的“匿名过程”也就是我们的Lambda表达式,所以上面的代码可以改造成: (define (g) (lambda (x) (+ x 1))) ((g) 2) 那么((g) 2)的运算结果就是((lambda (x) (+ x 1)) 2),最后运算结果为3。 2,牛顿法 学到这里,你可能需要复习一下高等数学的基本内容,包括“导数”和“微分”,高数的在线教材可以在这里找到:http://sxyd.sdut.edu.cn/gaoshu1/index.htm 关于牛顿法的介绍可以看这里:http://en.wikipedia.org/wiki/Newton%27s_method ,下面是程序: (define (close-enough? v1 v2) (< (abs (- v1 v2)) 0.000000001)) ;定义不动点函数 (define (fixed-point f first-guess) (define (try guess step-count) (let ((next (f guess))) (if (close-enough? guess next) next (try next (+ step-count 1))))) (try first-guess 0)) ;定义导数函数 (define (D f) (lambda (x dx) (/ (- (f (+ x dx)) (f x)) dx))) ;牛顿法 (define (newton g first-guess) (fixed-point (lambda (x) (- x (/ (g x) ((D g) x 0.000000001)))) first-guess)) ;平方 (define (square x) (* x x)) ;定义开方,来测试下牛顿法 (define (sq x) (newton (lambda (y) (- (square y) x)) 1.0)) (sq 5) 3,“一等公民” 这里列出了程序语言中作为“一等公民”的语言元素所具备的几个“特权”: 可以用变量命名 可以作为过程参数 可以作为过程返回结果 可以被包含在数据结构中 4,练习1.40 求三次方程 x^3 + ax^2 + bx + c 的零点。 首先,证明 函数f(x) = x^3 + ax^2 + bx + c 是“可微”的: 由可导和可微的性质知道,可导和可微互为充要条件,所以,要证可微我们可以先证可导, f ’ (x) = (x^3)’ + (ax^2)’ + (bx)’ + (c)’ = 3x^2 + 2ax + b 所以f(x)的导数存在,那么f(x)可导,其必定可微。 其次,利用“牛顿法”:如果f(x)是可微函数,那么f(x)=0的一个解就是函数(x – f(x)/df(x)的一个不动点,其中df(x)是f(x)的导数。所以我们可以轻松得到下面的代码: (define (close-enough? v1 v2) (< (abs (- v1 v2)) 0.000000001)) ;定义不动点函数 (define (fixed-point f first-guess) (define (try guess step-count) (let ((next (f guess))) (if (close-enough? guess next) next (try next (+ step-count 1))))) (try first-guess 0)) ;定义导数函数 (define (D f) (lambda (x dx) (/ (- (f (+ x dx)) (f x)) dx))) ;牛顿法 (define (newton g first-guess) (fixed-point (lambda (x) (- x (/ (g x) ((D g) x 0.000000001)))) first-guess)) ;定义cubic函数,也就是我们题目中所谓的f(x) (define (cubic a b c) (lambda (x) (+ (* x x x) (* a x x) (* b x) c))) ;随便定义几个系数 (define a 3) (define b 5) (define c 8) (define result (newton (cubic a b c) 1.0)) ;定义一个验证过程,让其验证得到的解,是否让方程成立 (define (validate x) (= 0 (+ (* x x x) (* a x x) (* b x) c))) ;输出结果 result ;验证结果 (validate result) 比如上面我们计算 x^3 + 3x^2 + 5x + 8 = 0, 其一个解为:-2.3282688556686084 .....
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值