简体   繁体   中英

Solve a polynomial for a given value x in scheme

I am passing a list of pairs which represent a polynomial and a value of 'x.' I need to write a Scheme function which evaluates the polynomial at x.

  i.e ('((1 . 3) (1 . 2) (1 . 1) (1 . 0)) = x^3 + x^2 + x + 1 

This is what I have so far:

(define (eval-poly p x)
    (+ 
       (* (car (car p)) x x x)
       (* (car (car (cdr p))) x x)
       (* (car (car (car (car p)))) x)
       (car (car (car (car (cdr p)))))
    ))

The lines (+ (* (car (car p)) xxx) and (* (car (car (cdr p))) xx) access and evaluate the first two pairs correctly, but I am unsure how to access the last two pairs in the list and evaluate them.

The first place OP code has gone astray is in the use of cdr . When in doubt about use of car and cdr , jump into the REPL and enter some test expressions to gain clarity. Given OP example polynomial p , OP solution would work if corrected:

;; Given p = '((1 . 3) (1 . 2) (1 . 1) (1 . 0))

(car p)                          =>  '(1 . 3)
(car (car p))                    =>  1
(cdr p)                          =>  '((1 . 2) (1 . 1) (1 . 0))
(car (cdr p))                    =>  '(1 . 2)
(car (car (cdr p)))              =>  1
(cdr (cdr p))                    =>  '((1 . 1) (1 . 0))
(car (cdr (cdr p)))              =>  '(1 . 1)
(car (car (cdr (cdr p))))        =>  1
(cdr (cdr (cdr p)))              =>  '((1 . 0))
(car (cdr (cdr (cdr p))))        =>  '(1 . 0)
(car (car (cdr (cdr (cdr p)))))  =>  1

So, changing a few car s to cdr s will be a step in the right direction:

(define (eval-poly p x)
    (+ 
       (* (car (car p)) x x x)
       (* (car (car (cdr p))) x x)
       (* (car (car (cdr (cdr p)))) x)
       (car (car (cdr (cdr (cdr p)))))))

This definition will work for OP example polynomial, but has deficiencies; it will only work for third degree polynomials where all terms are explicitly included. The OP approach will not work in general; these cases would fail:

;; p = '((2 . 3) (1 . 1))
;;
;; p = '((1 . 2) (2 . 1) (3 . 0))
;;
;; p = '((3 . 5) (2 . 3) (-1 . 1) (3 . 0))

A better implementation would take advantage of the fact that the representation of the polynomial captures the degree of each term in the cdr of the term. Also, a better implementation should not require a specific number of terms in the polynomial representation. We could achieve this by writing a procedure that evaluates a term, and mapping it over the polynomial.

(define (eval-term t x)
  (let ((coeff (car t))
        (deg (cdr t)))
    (* coeff (expt x deg))))

(define (eval-poly p x)
  (apply + (map (lambda (t) (eval-term t x)) p)))

Here a lambda expression is used to create a procedure that takes only a term t as its argument; that procedure is mapped over the polynomial, and apply is used to sum the results together. If eval-term is not needed elsewhere, it may be cleaner to define this inside of eval-poly :

(define (eval-poly p x)
  (define (eval-term t)
    (let ((coeff (car t))
          (deg (cdr t)))
      (* coeff (expt x deg))))
  (apply + (map eval-term p)))

This new definition will work for polynomials other than third degree, as well as for polynomials with omitted terms:

> (eval-poly '((1 . 3) (1 . 2) (1 . 1) (1 . 0)) 2)
15
> (eval-poly '((2 . 3) (1 . 1)) 2)
18
> (eval-poly '((1 . 2) (2 . 1) (3 . 0)) 2)
11
> (eval-poly '((3 . 5) (2 . 3) (-1 . 1) (3 . 0)) 2)
113

The obvious way to do this is with a syntactically-recursive function:

Given a current value:

  • if the polynomial specification is empty the result is that value
  • otherwise add whatever the car of the specification tells you to do to the value and process the cdr .

This is very natural in Scheme:

(define (eval-poly p x)
  ;; evaluate p on x
  (define (eval-poly/loop pt v)
    ;; evaluate pt on x with a current value of v
    (if (null? pt)                      ;we're done
        v
        (eval-poly/loop                 ;we're not done
         (cdr pt)
         (+ v (* (expt x (cdr (car pt)))
                 (car (car pt)))))))
  (eval-poly/loop p 0))                 ;initially the current value is 0

In a language with pattern matching this is possibly even more natural. This example is Racket:

(define (eval-poly p x)
  (define/match (eval-poly/loop pt v)
    (('() cv) cv)
    (((cons (cons power coeff) ptt) cv)
     (eval-poly/loop
      ptt
      (+ cv (* (expt x power) coeff))))
    ((_ _)
     (error 'eval-poly "bad poly specification ~S" p)))
  (eval-poly/loop p 0))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM