計算機程序的構造和解釋 練習題2.92

  說一下程序的思路,比如一個x變量的多項式 (2+y^2)* x ^3 + x^2+7,我們要把他轉化爲關於變量y的多項,怎麼來轉化?
  首先按照多項式的次數,分別進行轉化,第一項 (2+y^2)* x ^3 ,第二項 1x ^2,第三項
7**x ^0,。
  每一項的轉化思路,把次數和係數分別轉化成關於y變量的多項式,然後相乘,得到的多項式就是最終轉化爲y變量的多項式,也就是多項式(2+y^2) 乘以多項式(1
x ^3) * y ^0,每一項都按照這個思路進行轉化,就得到了最終的結果。
  接着我們寫出多項式係數轉化方法term-coeff->poly,多項式次數轉化term-order->poly
每一項的轉化term->poly,term->poly是將term-coeff->poly和term-order->poly結果相乘。
  最後再寫出變化變量的poly->poly過程。

另外我們還需要加一個強制,就是將數字轉化爲多項式的強制過程number->poly。這樣可以保證係數如果一個是多項式,另一個是數字之間的運算問題。
  具體實現如下。

(define (poly->poly p newvar)
   ;;把這一項的次數部分轉化成新變量的表達式,比如x^2轉化爲1*x^2*y^0的表達式。
  (define (term-order->poly order oldvar)
    (make-polynomial newvar 
                     (make-sparse-terms 
                      (list (make-term 0
                                       (make-polynomial oldvar 
                                                        (make-sparse-terms 
                                                         (list (make-term order 1)))))))))
 ;;把這一項的係數部分轉化成新變量的表達式,
 ;;如果係數是數字,轉化成關於新變量的多項式7*y^0;;如果係數是多項式且變量與新變量相同,直接採用該係數就可以。
 ;;如果係數是多項式且變量與新變量不相同,化成關於新變量y,係數爲多項式(6*z^3+z^2),次數y^0的多項式
  (define (term-coeff->poly coeff)
    (cond ((number? coeff) (number->poly coeff newvar))
           ((eq? (variable coeff) newvar) coeff)
           (else (make-polynomial newvar (make-sparse-terms (list (make-term 0 coeff)))))))
  ;;把這一項係數和次數轉化後的多項式相乘,得到的就是該項轉化後的結果
  (define (term->poly term oldvar)
    (mul (term-order->poly (order term) oldvar)
         (term-coeff->poly (coeff term))))
    
  (cond ((eq? (variable p) newvar) p)
        ((empty-terms? (term-list p)) (make-polynomial newvar (make-sparse-terms '())))
        ((add (term->poly (first-terms (term-list p)) (variable p)) 
              (poly->poly (make-polynomial (variable p) (make-sparse-terms (rest-terms (term-list p)))) newvar)))))
   ;;數字轉化爲多項式的方法
(define (number->poly n var)
  (make-polynomial var (make-sparse-terms (list (make-term 0 n)))))
(put-coercion 'scheme-number 'polynomial number->poly)

附上完整過程

#lang racket
;put get實現
(define *op-table* (make-hash))

(define (put op type proc)
  (hash-set! *op-table* (list op type) proc))

(define (get op type)
  (hash-ref *op-table* (list op type) #f))

(define *type-coercion* (make-hash))

(define (put-coercion type1 type2 proc)
  (hash-set! *type-coercion* (list type1 type2) proc))

(define (get-coercion type1 type2)
  (hash-ref *type-coercion* (list type1 type2) #f))

(define (attach-tag type-tag contents)
  (cond ((eq? type-tag 'scheme-number) contents)
        (else (cons type-tag contents))))

(define (type-tag datum)
  (cond ((number? datum) 'scheme-number)
        ((pair? datum) (car datum))
        (else (error "Bad tagged datum -- TYPE-TAG" datum))))

(define (contents datum)
   (cond ((number? datum) datum)
         ((pair? datum) (cdr datum))
         (else (error "Bad tagged datum -- CONTENTS" datum))))

(define (apply-generic op . args)
  (let ((type-tags (map type-tag args)))
    (let ((proc (get op type-tags)))
      (if proc
          (apply proc (map contents args))
          (if (= (length args) 2)
              (let ((type1 (car type-tags))
                    (type2 (cadr type-tags))
                    (a1 (car args))
                    (a2 (cadr args)))
                (let ((t1->t2 (get-coercion type1 type2))
                      (t2->t1 (get-coercion type2 type1)))
                  (cond (t1->t2
                         (apply-generic op (t1->t2 a1 (variable a2)) a2))
                        (t2->t1
                         (apply-generic op a1 (t2->t1 a2 (variable a1))))
                        (else
                         (error "No method for these types"
                                (list op type-tags))))))
              (error "No method for these types"
                     (list op type-tags)))))))

(define (add x y) (apply-generic 'add x y))
(define (sub x y) (apply-generic 'sub x y))
(define (mul x y) (apply-generic 'mul x y))
(define (div x y) (apply-generic 'div x y))
(define (=zero? x) (apply-generic '=zero? x))
(define (coeff-all-zero? x) (apply-generic 'coeff-all-zero? x))

(define (install-scheme-number-package)
  (define (tag x)
    (attach-tag 'scheme-number x))
  (put 'add '(scheme-number scheme-number)
       (lambda (x y) (tag (+ x y))))
  (put 'sub '(scheme-number scheme-number)
       (lambda (x y) (tag (- x y))))
  (put 'mul '(scheme-number scheme-number)
       (lambda (x y) (tag (* x y))))
  (put 'div '(scheme-number scheme-number)
       (lambda (x y) (tag (/ x y))))
  (put '=zero? '(scheme-number)
       (lambda (x) (= x 0)))
  (put 'make 'scheme-number
       (lambda (x) (tag x)))
  'done)
(define (make-scheme-number n)
  ((get 'make 'scheme-number) n))

(define (install-polynomial-package)
  (define (make-poly variable term-list)
    (cons variable term-list))
  (define (variable p) (car p))
  (define (term-list p) (cdr p))
  (define (add-poly p1 p2)
    (if (same-variable? (variable p1) (variable p2))
        (make-poly (variable p1)
                   (add (term-list p1)
                        (term-list p2)))
        (add-poly p1 (contents (poly->poly (tag p2) (variable p1))))))
  (define (sub-poly p1 p2)
    (if (same-variable? (variable p1) (variable p2))
        (make-poly (variable p1)
                   (sub (term-list p1)
                        (term-list p2)))
        (sub-poly p1 (contents(poly->poly (tag p2) (variable p1))))))
  (define (mul-poly p1 p2)
    (if (same-variable? (variable p1) (variable p2))
        (make-poly (variable p1)
                   (mul (term-list p1)
                        (term-list p2)))
        (mul-poly p1 (contents(poly->poly (tag p2) (variable p1))))))
  (define (div-poly p1 p2)
    (if (same-variable? (variable p1) (variable p2))
        (make-poly (variable p1)
                   (div (term-list p1)
                        (term-list p2)))
        (div-poly p1 (contents(poly->poly (tag p2) (variable p1))))))
  (define (=zero-poly? poly)
    (coeff-all-zero? (term-list poly)))
  (define (tag p) (attach-tag 'polynomial p))
  (put 'add '(polynomial polynomial)
       (lambda (p1 p2) (tag (add-poly p1 p2))))
  (put 'mul '(polynomial polynomial)
       (lambda (p1 p2) (tag (mul-poly p1 p2))))
  (put 'sub '(polynomial polynomial)
       (lambda (p1 p2) (tag (sub-poly p1 p2))))
  (put 'div '(polynomial polynomial)
       (lambda (p1 p2) (tag (div-poly p1 p2))))
  (put 'variable '(polynomial)
       (lambda (p) (variable p)))
  (put 'term-list '(polynomial)
       (lambda (p) (term-list p)))
  (put '=zero? '(polynomial) =zero-poly?)
  (put 'make 'polynomial
       (lambda (var terms) (tag (make-poly var terms))))
  'done)

(define (poly->poly p newvar)
   ;;把這一項的指數部分轉化成舊變量的表達式,比如3*x^2轉化爲係數爲1*x^2*y^0的表達式,用來作爲新變量的係數。
  (define (term-order->poly order oldvar)
    (make-polynomial newvar 
                     (make-sparse-terms 
                      (list (make-term 0
                                       (make-polynomial oldvar 
                                                        (make-sparse-terms 
                                                         (list (make-term order 1)))))))))
  (define (term-coeff->poly coeff)
    (cond ((number? coeff) (number->poly coeff newvar))
           ((eq? (variable coeff) newvar) coeff)
           (else (make-polynomial newvar (make-sparse-terms (list (make-term 0 coeff)))))))
        
  (define (term->poly term oldvar)
    (mul (term-order->poly (order term) oldvar)
         (term-coeff->poly (coeff term))))
    
  (cond ((eq? (variable p) newvar) p)
        ((empty-terms? (term-list p)) (make-polynomial newvar (make-sparse-terms '())))
        ((add (term->poly (first-terms (term-list p)) (variable p)) 
              (poly->poly (make-polynomial (variable p) (make-sparse-terms (rest-terms (term-list p)))) newvar)))))
   
(define (number->poly n var)
  (make-polynomial var (make-sparse-terms (list (make-term 0 n)))))
(put-coercion 'scheme-number 'polynomial number->poly)
 

(define (install-sparse-polynomial-package)
  (define (add-terms L1 L2)
    (cond ((empty-termlist? L1) L2)
          ((empty-termlist? L2) L1)
          (else
           (let ((t1 (first-term L1)) (t2 (first-term L2)))
             (cond ((> (order t1) (order t2))
                    (adjoin-term
                     t1 (add-terms (rest-terms L1) L2)))
                   ((< (order t1) (order t2))
                    (adjoin-term
                     t2 (add-terms L1 (rest-terms L2))))
                   (else
                    (adjoin-term
                     (make-term (order t1) 
                                (add (coeff t1) (coeff t2)))
                     (add-terms (rest-terms L1)
                                (rest-terms L2)))))))))
  (define (sub-terms L1 L2)
    (cond ((empty-termlist? L1) L2)
          ((empty-termlist? L2) L1)
          (else
           (let ((t1 (first-term L1)) (t2 (first-term L2)))
             (cond ((> (order t1) (order t2))
                    (adjoin-term
                     t1 (sub-terms (rest-terms L1) L2)))
                   ((< (order t1) (order t2))
                    (adjoin-term
                     (make-term (order t2) (- 0 (coeff t2))) (sub-terms L1 (rest-terms L2))))
                   (else
                    (adjoin-term
                     (make-term (order t1) 
                                (sub (coeff t1) (coeff t2)))
                     (sub-terms (rest-terms L1)
                                (rest-terms L2)))))))))
  (define (mul-terms L1 L2)
    (if (empty-termlist? L1)
        (the-empty-termlist)
        (add-terms (mul-term-by-all-terms (first-term L1) L2)
                   (mul-terms (rest-terms L1) L2))))
  (define (mul-term-by-all-terms t1 L)
    (if (empty-termlist? L)
        (the-empty-termlist)
        (let ((t2 (first-term L)))
          (adjoin-term
           (make-term (+ (order t1) (order t2))
                      (mul (coeff t1) (coeff t2)))
           (mul-term-by-all-terms t1 (rest-terms L))))))
  (define (div-terms L1 L2)
    (if (empty-termlist? L1)
        (list (the-empty-termlist) (the-empty-termlist))
        (let ((t1 (first-term L1))
              (t2 (first-term L2)))
          (if (> (order t2) (order t1))
              (list (the-empty-termlist) L1)
              (let ((new-c (div (coeff t1) (coeff t2)))
                    (new-o (- (order t1) (order t2))))
                (if (=zero? new-c)
                     (list (the-empty-termlist) L1)
                     (let ((rest-of-result (div-terms (sub-terms L1 (mul-term-by-all-terms (make-term new-o new-c) L2)) L2)))
                       (list (adjoin-term (make-term new-o new-c) (car rest-of-result)) (cadr rest-of-result))
                       )))))))
                                   

  (define (coeff-all-zero? term-list)
      (if (empty-termlist? term-list)
          #t
          (if (=zero? (coeff (first-term term-list)))
              (coeff-all-zero? (rest-terms term-list))
              #f)))
  (define (the-empty-termlist) '())
  (define (first-term term-list) (car term-list))
  (define (rest-terms term-list) (cdr term-list))
  (define (empty-termlist? term-list) (null? term-list))
  (define (make-term order coeff) (list order coeff))
  (define (order term) (car term))
  (define (coeff term) (cadr term))
  (define (tag p) (attach-tag 'sparse p))
  (put 'coeff-all-zero? '(sparse)
       (lambda (p1) (coeff-all-zero? p1)))
  (put 'add '(sparse sparse)
       (lambda (p1 p2) (tag (add-terms p1 p2))))
  (put 'mul '(sparse sparse)
       (lambda (p1 p2) (tag (mul-terms p1 p2))))
  (put 'sub '(sparse sparse)
       (lambda (p1 p2) (tag (sub-terms p1 p2))))
  (put 'div '(sparse sparse)
       (lambda (p1 p2) (tag (div-terms p1 p2))))
  (put 'order 'term
       (lambda (p) (order p)))
  (put 'coeff 'term
       (lambda (p) (coeff p)))
  (put 'make 'term
       (lambda (p t) (make-term p t)))
  (put 'rest-terms '(sparse)
       (lambda (p) (rest-terms p)))
   (put 'empty-terms '(sparse)
       (lambda (p) (empty-termlist? p)))
  (put 'first-terms '(sparse)
       (lambda (p) (first-term p)))
  (put 'make 'sparse
       (lambda (terms) (tag terms)))
  'done)
(define (adjoin-term term term-list)
  (if (=zero? (coeff term))
      term-list
      (cons term term-list)))
(define (variable x) 
  (apply-generic 'variable x))
(define (term-list x) 
  (apply-generic 'term-list x))
(define (order term)
  ((get 'order 'term) term))
(define (coeff term)
  ((get 'coeff 'term) term))
(define (make-term order coeff)
  ((get 'make 'term) order coeff))
(define (rest-terms term-list)
  (apply-generic 'rest-terms term-list))
(define (first-terms term-list)
  (apply-generic 'first-terms term-list))
(define (make-polynomial var terms)
  ((get 'make 'polynomial) var terms))
(define (make-sparse-terms terms)
  ((get 'make 'sparse) terms))
(define (empty-termlist? term-list) (null? term-list))

(define (empty-terms? terms)
  (apply-generic 'empty-terms terms))

(define (same-variable? v1 v2)
  (define (variable? x) (symbol? x))
  (and (variable? v1) (variable? v2) (eq? v1 v2)))
(install-scheme-number-package)
(install-polynomial-package)
(install-sparse-polynomial-package)
(define sparse-polynumial-A (make-polynomial 'x (make-sparse-terms '((5 1) (0 -1)))))
(define sparse-polynumial-B (make-polynomial 'y (make-sparse-terms '((2 1) (0 -1)))))
(add sparse-polynumial-A sparse-polynumial-B)
(sub sparse-polynumial-A sparse-polynumial-B)
(mul sparse-polynumial-A sparse-polynumial-B)

運行過程,因爲除法所得到的結果是由商和餘數組成,它的結構和其他幾種運算不同,所以暫時未實現。下面是運行結果。

'done
'done
'done
'(polynomial x sparse (5 1) (0 (polynomial y sparse (2 1) (0 -2))))
'(polynomial x sparse (5 1) (0 (polynomial y sparse (2 -1))))
'(polynomial x sparse (5 (polynomial y sparse (2 1) (0 -1))) (0 (polynomial y sparse (2 -1) (0 1))))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章