アーカイブ

‘数式処理’ タグのついている投稿

[数式処理][Scheme] 算術式を簡単にする

2011 年 11 月 6 日 コメントはありません

微分などで複雑になった算術式を簡素化するには次のようにする。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
(define (simple exp)
  (define (flat lst op)
    (append-map! (lambda (x)
                   (if (and (pair? x) (eq? (car x) op))
                       (flat (cdr x) op)
                       (list x)))
                 lst))
 
  (define (constant-fold args init op)
    (define (cf args num acc)
      (cond ((null? args)
             (values acc num))
            ((number? (car args))
             (cf (cdr args) (op num (car args)) acc))
            (else
             (cf (cdr args) num (append! acc (list (car args)))))))
    (cf args init '() ))
 
  (define (simple-+ args)
    (set! args (map simple args))
    (set! args (flat args '+))
    (receive (exps num) (constant-fold args 0 +)
     (cond ((null? exps) num)
           (else `(+ ,@args num)))))
 
  (define (simple-* args)
    (call/cc
     (lambda (c)
       (set! args (map simple args))
       (set! args (flat args '*))
       (map (lambda (x)
              (when (and (number? x) (= x 0))
                    (c 0)))
            args)
       (set! args (constant-fold args 1 *))
       (set! args (remove (lambda (x)
                            (and (number? x)(= x 1)))
                          args))
       (if (= 1 (length args))
           (car args)
           `(* ,@args)))))
 
  (define (simple-expt base ex)
    (set! base (simple base))
    (set! ex (simple ex))
    (cond ((or (and (number? base) (= base 1))
               (and (number? ex) (= ex 0)))
           1)
          ((or (and (number? base) (= base 0))
               (and (number? ex) (= ex 1)))
           base)
          (else
           `(expt ,base ,ex))))
 
  (define (simple-- arg)
    (cond ((number? arg) (- arg))
          ((and (pair? arg)
                (eq? (car arg) '+))
           (simple-+ (map (lambda (x) (list '- x))
                          (cdr arg))))
          ((and (pair? arg)
                (eq? (car arg) '*))
           (simple-* (map (lambda (x) (list '- x))
                          (cdr arg))))
          (else
           `(- ,arg))))
 
  (cond ((not (pair? exp)) exp)
        ((eq? (car exp) '-)
         (simple-- (cadr exp)))
        ((eq? (car exp) '+)
         (simple-+ (cdr exp)))
        ((eq? (car exp) '*)
         (simple-* (cdr exp)))
        ((eq? (car exp) 'expt)
         (simple-expt (cadr exp) (caddr exp)))
        (else
         `(,(car exp) ,@(map simple (cdr exp))))))
> (simple (deriv '(expt (* (sin x) (cos x)) 1/2) 'x))
=> (* (expt (* (sin x) (cos x)) -1/2) (+ (* (cos x) (cos x)) (* (sin x) (- (sin x)))) 1/2)

`-’ 演算子は単項演算子としてのみ使える。

カテゴリー: コンピュータ タグ: , ,

[数式処理][Scheme] 微分する

2011 年 11 月 6 日 コメントはありません

複雑な微分をするときは計算機に任せた方が良いように思う。

Scheme で微分するには次のようにする。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(define (deriv exp var)
  (cond ((eq? exp var) 1)
	((not (pair? exp)) 0)
	((eq? (car exp) '-)
	 `(- ,(deriv (cadr exp) var)))
	((eq? (car exp) '+)
	 `(+ ,(deriv (cadr exp) var) ,(deriv (caddr exp) var)))
	((eq? (car exp) '*)
	 `(+ (* ,(deriv (cadr exp) var)
		,(caddr exp))
	     (* ,(cadr exp)
		,(deriv (caddr exp) var))))
	((eq? (car exp) 'expt)
	 (let ((g (cadr exp))
	       (n (caddr exp)))
	   `(* (* ,n (expt ,g ,(- n 1))) ,(deriv g var))))
	((eq? (car exp) 'sin)
	 `(* (cos ,(cadr exp)) ,(deriv (cadr exp) var)))
	((eq? (car exp) 'cos)
	 `(* (- (sin ,(cadr exp))) ,(deriv (cadr exp) var)))
        ((eq? (car exp) 'tan)
         `(* (+ 1 (expt ,exp 2)) ,(deriv (cadr exp) var)))
	(else (error "not yet."))))
> (deriv '(expt (* (sin x) (cos x)) 1/2)) 'x)
=> (* (* 1/2
         (expt (* (sin x) (cos x)) -1/2))
      (+ (* (* (cos x) 1)
	    (cos x))
         (* (sin x)
	    (* (- (sin x)) 1))))

`-’ 演算子は単項演算子としてのみ使える。

カテゴリー: コンピュータ タグ: , ,