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:
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.