SICP有个缺点:不利于我们跳读。
当我想忽略或快速浏览某些章节后,阅读《2.3符号数据》,又逼得我不得不回头找一下某些东西。
例如
练习2.53中提到的cadr,我得回头查一查;
练习2.54中,如何判断表的一个元素是否表,是否符号?我不会耶!!!2.3.2中提到判断表达式是否数值的基本函数number?,应该有相关的基本过程吧,那里提到了呢?晕,在<代数表达式的表示>中提到了symbol?,
还能不能让我好好玩耍?
本节对我们应该有点吸引力,因为在《编程导论(Java)•0.1.1 计算简史*》中提到:“莱布尼茨的梦想:符号可以像数字一样进行推导和演算。这就是符号系统的计算!”但是《编程导论(Java)》并没有涉及这一部分(如多项式)。
符号求导对于Lisp有着特殊的历史意义,也是符号计算(symbolic computation)的经典例子。例如ax2 +bxy+z表达式对x求导,将获得2ax+by。SICP给出了计算+和*构成的表达式的求导程序。
1.被求导的表达式,按照前缀形式表示。练习2.58要求完成中缀表示,但是会有更多的困难,如省略的括号和优先级问题。
2.前缀表示时的基本函数:需要提取被求导的表达式的各个符号(求和式子、求积式子、常量、变量),将结果组合成表达式。
;x是变量? (define (variable? x) (symbol? x)) ; (define (same-variable? v1 v2) (and (variable? v1) (variable? v2) (eq? v1 v2))) ; (define (make-sum a1 a2) (list '+ a1 a2)) (define (make-product m1 m2) (list '* m1 m2)) (define (sum? x) (and (pair? x) (eq? (car x) '+))) (define (addend s) (cadr s)) (define (augend s) (caddr s)) (define (product? x) (and (pair? x) (eq? (car x) '*))) (define (multiplier p) (cadr p)) (define (multiplicand p) (caddr p))3.求导函数
(define (deriv exp var) (cond ((number? exp) 0) ((variable? exp) (if (same-variable? exp var) 1 0)) ((sum? exp) (make-sum (deriv (addend exp) var) (deriv (augend exp) var))) ((product? exp) (make-sum (make-product (multiplier exp) (deriv (multiplicand exp) var)) (make-product (deriv (multiplier exp) var) (multiplicand exp)))) (else (error "unknown expression type -- DERIV" exp))))(deriv '(+ x 3) 'x)→ (+ 1 0) ;(x+3)' =1+0
(deriv '(* x y) 'x)→(+ (* x 0) (* 1 y)) ; (xy)' =0*x+1*y
(deriv '(* (* x y) (+ x 3)) 'x)→
(+ (* (* x y) (+ 1 0))
(* (+ (* x 0) (* 1 y))
(+ x 3)))
;(xy*(x+3))'=(xy*(1+0)+(0*x+1*y)*(x+3))=xy+y(x+3)
对结果进行简化是一个目标。
自己写解释器。
package algorithm.deriv; import static tips.Print.*;//p(x) = System.out.print(x) /** 求一元多项式的导数。 系数为int便于实现。 */ public class Polynomial{//多项式 private static class Node{ public int coef;//coefficient public int exp;//指数 public Node next; public Node(int coef,int exp){ this.coef=coef; this.exp=exp; } public Node setNext(int coef,int exp){ this.next=new Node(coef,exp); return this.next; } } public static Node getDeriv(Node head){ Node derivHead = null;//导数链表的头结点 Node p = null; int _coef,_exp;//导数结点的域 while(head!=null){ if(head.exp!=0){ _coef = head.exp*head.coef; _exp=head.exp-1; p =(derivHead==null)? (derivHead=new Node(_coef,_exp)): p.setNext(_coef,_exp); } head = head.next; } return derivHead; } public static void printList(Node head) { while(head!=null){ p(head.coef); if(head.exp!=0){ String s = (head.exp==1)?"x":"x^"+head.exp; p(s); } if(head.next!=null&&head.next.coef>0) p(" + ");//负号自带 head=head.next; } pln(); } public static void test() { Node head=new Node(6,5); Node p=head.setNext(-2,3); p=p.setNext(3,2); p=p.setNext(-1,0); p=null;//已到尾节点 p("f(x) = "); printList(head); Node derivHead=getDerivatives(head); p("f(x)'= "); printList(derivHead); } }