如何在方案中将两个多项式列表相乘

时间:2018-12-03 21:20:52

标签: scheme

我正在寻找有关如何将两个多项式列表相乘的提示,例如如何创建函数  (poly_mul'(3 4 5)'(5 9 6 2))输出应为(15 47 79 75 38 10)

我到目前为止所拥有的:

(define (poly-mul lst1 lst2)
(let loop ((expo 0) (l1 lst1) (l2 lst2))
(cond ((null? l1) '())
      ((null? l2) (loop expo (cdr l1) lst2))
      (else (cons (* (car l1) (car l2))
                  (loop expo l1 (cdr l2)))))))

3 个答案:

答案 0 :(得分:1)

您可以将poly-mult视为递归poly-add。鉴于易于实现的poly-add

(define (poly-add p1 p2)
  (cond ((empty? p1)
         p2)
        ((empty? p2)
         p1)
        (else
         (cons (+ (car p1)
                  (car p2))
               (poly-add (cdr p1)
                         (cdr p2))))))

您可以使用poly-mult帮助程序来实现raise

(define (poly-mul p1 p2 (e 0))
  (if (empty? p1)
      empty
      (poly-add (raise e (map (curry * (car p1)) p2))
                (poly-mul (cdr p1)
                          p2
                          (+ e 1)))))

(define (raise e p)
  (if (= e 0)
      p
      (cons 0
            (raise (- e 1)
                   p))))

(poly-mul '(3 4 5) '(5 9 6 2))
;; '(15 47 79 75 38 10)

通过将raise定义为外部过程,很容易看出我们如何将多项式提高到下一个幂。但是,我们可以通过使用循环并将指数(poly-mult)用作函数本身来将这种行为包含在e内部。

(define (poly-mul p1 p2)
  (let loop ((p p1)         ;; polynomial
             (e identity))  ;; exponent
    (if (empty? p)
        empty
        (poly-add (e (map (curry * (car p)) p2))
                  (loop (cdr p)
                        (compose (curry cons 0) e))))))

(poly-mul '(3 4 5) '(5 9 6 2))
;; '(15 47 79 75 38 10)

最后,在poly-mult中使用循环使我们很容易将递归调用转换为适当的尾调用。现在首先进行poly-add操作,并将更新的累加器(acc)分配给下一个循环迭代。

(define (poly-mul p1 p2)
  (let loop ((acc empty)   ;; accumulator
             (p p1)        ;; polynomial
             (e identity)) ;; exponent
    (if (empty? p)
        acc
        (loop (poly-add acc
                        (e (map (curry * (car p)) p2)))
              (cdr p)
              (compose (curry cons 0) e)))))

答案 1 :(得分:0)

您找到了一种将数字相乘的方法。现在,您需要像平时在纸上那样添加带有移位索引的文件:

 15 27 18 06 00 00
 00 20 36 24 08 00
 00 00 25 45 30 10

使用向量将更容易,例如,使用列表求和时附加零:

(define polynomial-mul
  (lambda (lst1 lst2)    
    (let ((tmp 
           (map (lambda (n) 
              (map (lambda (m) 
                     (* n m)) 
                   lst2)) lst1)))
      (let loop ((z '(0)) (l (car tmp)) (r (cdr tmp)))
        (cond
         ((null? r) l)
         (else
          (loop (cons 0 z) 
                (map + 
                     (append l '(0))
                     (append z (car r)))
                (cdr r))))))))            

但是由于添加,这是非常低效的。最好使用辅助功能来移动两个列表:

(define shifted-map
  (lambda (f shift lst1 lst2)
    (cond
     ((and (not (null? lst1)) (not (zero? shift))) 
      (cons (car lst1) 
            (shifted-map f (sub1 shift) (cdr lst1) lst2)))
     ((null? lst2) lst1)
     (else
      (cons (f (car lst1) (car lst2))
            (shifted-map f shift (cdr lst1) (cdr lst2)))))))

(define polynomial-mul
  (lambda (lst1 lst2)    
    (let ((tmp 
           (map (lambda (n) 
              (map (lambda (m) 
                     (* n m)) 
                   lst2)) lst1)))
      (let loop ((shift 1) (l (car tmp)) (r (cdr tmp)))
        (cond
         ((null? r) l)
         (else
          (loop  
           (add1 shift)
           (shifted-map + shift l (car r))
           (cdr r))))))))

答案 2 :(得分:0)

使用SRFI-1的fold-right,它就像从中学数学中一样,是一个从右到右的缩放和加法循环:

(require srfi/1)

(define (multpoly p1 p2)
  (fold-right
      (lambda (a r)
         (addpoly (map (lambda (b) (* a b)) p2)  ; map (a*) p
                  (cons 0 r)))
      '() p1))

其中

(define (addpoly p1 p2)
  (cond ((null? p1) p2)
        ((null? p2) p1)
        (else (cons (+       (car p1) (car p2))
                    (addpoly (cdr p1) (cdr p2))))))