    CS 171 & 171L Introduction to Computer Science I & Lab Fall 2020     ## Lab 9: Polynomials

In this lab you will familiarize yourself with the java representation of objects and arrays by working with a class which supports polynomial functions.

### Polynomial functions

A polynomial $$p$$ is a function of the form \begin{align} p(x) &= a_nx^n + a_{n-1}x^{n-1} + \cdots + a_i x^i + \cdots + a_2 x^2 + a_1 x + a_0 \\ &= \underbrace{a_0 + a_1 x + a_2 x^2 + \cdots + a_i x^i + \cdots + a_{n-1}x^{n-1} +a_nx^n}_{(n+1) \text{ terms}} \\ &= \sum_{i=0}^n a_i x^i \quad(\text{recall } x^0 = 1) \end{align} where the values $$a_0$$, $$a_1$$, $$\ldots$$, $$a_n \ne 0$$ are constants called the coefficients of $$p$$, with $$a_i$$ being the $$i$$th coefficient. Here we will assume the constants are real numbers, but they could be complex numbers or other mathematical entities. The degree of $$p$$ is $$n$$.

The zero polynomial is just $$p(x) = 0$$ and its degree is undefined (or sometimes -1).

Negating a polynomial multiplies all coefficients by -1. \begin{align} -p(x) &= -a_0 + -a_1 x + -a_2 x^2 + \cdots + -a_i x^i + \cdots + -a_{n-1}x^{n-1} + -a_nx^n \\ &= -a_0 - a_1 x - a_2 x^2 - \cdots - a_i x^i - \cdots - a_{n-1}x^{n-1} - a_nx^n. \end{align}

Mulitplying a polynomial by a constant $$b$$ multiplies all coefficients by $$b$$. \begin{align} b p(x) &= b a_0 + b a_1 x + b a_2 x^2 + \cdots + b a_i x^i - \cdots + b a_{n-1}x^{n-1} + b a_nx^n. \end{align}

In evaluating the a polynomial $$p$$, you should try and be as efficient as possible. If you compute all the powers of $$x$$ and don't save any intermediate results, that is not very efficient. Instead use an additional variable to store $$x^i$$ and just multiply by $$x$$ every pass of the loop. Another way is called Horner's method, which is related to synthetic division.

Given two polynomials p and q with degrees $$n$$ and $$m$$ respectively with $$n < m$$. Thus $p(x) = a_0 + a_1 x + a_2 x^2 + \cdots + a_i x^i + \cdots + a_{n-1}x^{n-1} + a_nx^n$ and $q(x) = b_0 + b_1 x + b_2 x^2 + \cdots + b_i x^i + \cdots + b_{n-1}x^{n-1} + b_nx^n + \cdots + b_{m-1}x^{m-1} + b_mx^m.$ then $p(x) + q(x) = (a_0 + b_0) + (a_1 + b_1) x + (a_2 + b_2) x^2 + \cdots + (a_{n}+ b_{n}) x^{n} + b_{n+1} x^{n+1} + \cdots + b_{m-1}x^{m-1} + b_mx^m.$ Multiplying two polynomials is more challenging. $r(x) = p(x)q(x) = a_0 q(x) + a_1 q(x) + \cdots + a_n q(x)$ Note that the resulting polynomial $$r$$ has degree $$m+n$$ with $$c_i$$ being the $$i$$th coefficient of $$r$$, which results from adding all $$a_j$$ and $$b_k$$ such that $$i = j+k$$, so $c_i = a_0 b_i + a_1 b_{i-1} + \cdots + a_{i-1} b_1 + a_i b_0 = \sum_{j = 0}^i a_j b_{(i-j)}.$ You will need two nested loops for this.

The derivative of a polynomial, denoted $$p'(x)$$ is given by $p'(x) = a_1 + 2 a_2 x + 3 a_3 x^2 + \cdots + i a_i x^{i-1} + \cdots + n a_n x^{n-1} = \sum_{i=1}^{n} i a_{i} x^{i-1}.$ This new polynomial has degree $$n-1$$. Note the limits on the summation.

The indefinite integral of a polynomial, denoted by $$P(x)$$ or $$\int p(x)\,dx$$, is given by $P(x) = \int p(x)\,dx = C + a_0 x + \dfrac{a_1}{2} x^2 + \dfrac{a_2}{3} x^3 + \cdots + \dfrac{a_{i-1}}{i} x^{i} + \cdots + \dfrac{a_{n}}{n+1} x^{n+1} = C + \sum_{i=1}^{n+1} \dfrac{a_{i-1}}{i} x^{i}.$ This new polynomial has degree $$n+1$$. In our case we are assuming $$C = 0$$. Note the limits on the summation.

The definite integral of the function $$p$$ from $$x_0$$ to $$x1$$ , is given by $\int_{x_0}^{x_1} p(x)\,dx = P(x_1) - P(x_0)$ where $$P(x)$$ is the indefinite integral defined above.

Complete the methods in Polynomial.pde, as shown below. After you complete each method, demonstrate it to your instructor. Change the driver/navigator roles after each method.
  // Lab 9 // Globals to allow persistence // setting bounds on our "world" coordinates float xmin = -10; float xmax = 10; float ymin = -10; float ymax = 10; // screen bound coordinates float umin = 0; float umax = 900; float vmin = 900; float vmax = 0; Polynomial p[] = new Polynomial; void settings() { size(900, 900); } void setup() { reset(); testing(); noLoop(); // no animation } void reset() { // setting bounds on our "world" coordinates xmin = -10; xmax = 10; ymin = -10; ymax = 10.0; } void testing() { int n = 0; p[n++] = new Polynomial(); // p(x) = 0; p[n++] = new Polynomial(new double[] {1.0}); // p(x) = 1; p[n++] = new Polynomial(new double[] {2.0, -1.0}); // p(x) = -x + 2; p[n++] = new Polynomial(new double[] {6.0, 5.0, 1.0}); // p(x) = x^2 + 5x + 6; p[n++] = new Polynomial(new double[] {1.0, 5.0, 7.0, 3.0}); // p(x) = 3x^3 + 7x^2 + 5x + 1 for (int i = 0; i < n; i++) { System.out.println("p(x) = " + p[i]); System.out.println("degree: " + p[i].degree()); Polynomial r = new Polynomial(p[i]); System.out.println("r(x) = " + r); System.out.println("degree: " + r.degree()); System.out.printf("p(%f) = %f = %f\n", 0.0, p[i].f(0.0), p[i].coeff(0)); System.out.printf("p(%f) = %f\n", 1.0, p[i].f(1.0)); System.out.printf("p(%f) = %f\n", -1.0, p[i].f(-1.0)); Polynomial q = p[i].derivative(); System.out.println("p'(x) = " + q); System.out.println("p' degree: " + q.degree()); q = p[i].integrate(); System.out.println("P(x) = " + q); System.out.println("P degree: " + q.degree()); double v = p[i].integral(1.0, 2.0); System.out.println("integral from 1.0 to 2.0 = " + v); r = p[i].negate(); System.out.println("-p(x) = " + r); System.out.println("degree: " + r.degree()); r = p[i].multiply(2.0); System.out.println("p(x) * 2 = " + r); System.out.println("degree: " + r.degree()); r = Polynomial.multiply(p[i], p[(i-1+n)%n]); System.out.println("(" + p[i] + ") * (" + p[(i-1+n)%n] + ") = " + r); System.out.println("degree: " + r.degree()); r = Polynomial.add(p[i], p[(i-1+n)%n]); System.out.println("(" + p[i] + ") + (" + p[(i-1+n)%n] + ") = " + r); System.out.println("degree: " + r.degree()); System.out.println("--------------------------------------------------------"); } } void draw() { background(224); axes(); // draw x and y axes strokeWeight(0.5); stroke(128); grid(1, 1); // draw grid strokeWeight(1); stroke(0); grid(5, 5); // draw grid drawLabels(5, 5); float x = map(mouseX, umin, umax, xmin, xmax); strokeWeight(4); for (int i = 0; i < p.length; i++) { if (p[i] == null) continue; stroke(random(1), random(1), random(1)); plot(p[i]); Line L = p[i].tangent(x); strokeWeight(3); plot(L); } } void plot(Polynomial p) { if (p == null) return; float x = xmin; float dx = (xmax-xmin)/width; float u1 = 0; float v1 = 0; float u2 = 0; float v2 = 0; boolean first = true; while (x <= xmax) { float y = (float) p.f(x); // x to u u2 = map(x, xmin, xmax, umin, umax); // y to v v2 = map(y, ymin, ymax, vmin, vmax); point(u1, v1); if (!first) { line(u1, v1, u2, v2); } else { first = false; } x += dx; // saving for next iteration u1 = u2; v1 = v2; } } void plot(Point2D p) { if (p == null) return; // no point to plot strokeWeight(6); float u = map(p.x, xmin, xmax, umin, umax); float v = map(p.y, ymin, ymax, vmin, vmax); ellipse(u, v, 6, 6); } void plot(Line L) { if (L == null) return; strokeWeight(4); float x = xmin; float dx = (xmax-xmin)/width; float u1 = 0; float v1 = 0; float u2 = 0; float v2 = 0; boolean first = true; while (x <= xmax) { float y = L.f(x); // x to u u2 = map(x, xmin, xmax, umin, umax); // y to v v2 = map(y, ymin, ymax, vmin, vmax); point(u1, v1); if (!first) { line(u1, v1, u2, v2); } else { first = false; } x += dx; // saving for next iteration u1 = u2; v1 = v2; } } void axes() { strokeWeight(2); stroke(0); // x-axis is a horizontal line at y = 0 and from xmin to xmax // need: line(xmin, y, xmax, y) // map from world coordinates onto screen coordinates float v = map(0, ymin, ymax, vmin, vmax); line(umin, v, umax, v); // y-axis is a verical line at x = 0 and from ymin to ymax // need: line(ymin, x, ymax, x) float u = map(0, xmin, xmax, umin, umax); line(u, vmin, u, vmax); } // draw a grid with dx and dy spacing void grid(float dx, float dy) { // vertical lines float x = 0; while (x <= xmax) { float u = map(x, xmin, xmax, umin, umax); // map x to u line(u, vmin, u, vmax); // draw vertical line x += dx; //increment x } x = 0; while (x >= xmin) { float u = map(x, xmin, xmax, umin, umax); // map x to u line(u, vmin, u, vmax); // draw vertical line x -= dx; //decrement x } // horizontal lines for (float y = 0; y <= ymax; y += dy) { float v = map(y, ymin, ymax, vmin, vmax); // map y to v line(umin, v, umax, v); // draw horizontal line } for (float y = 0; y >= ymin; y -= dy) { float v = map(y, ymin, ymax, vmin, vmax); // map y to v line(umin, v, umax, v); // draw horizontal line } } void drawLabels(float dx, float dy) { textSize(16); fill(0); float u = map(0, xmin, xmax, umin, umax); float v = map(0, ymin, ymax, vmin, vmax); text("0", u, v); for (float x = dx; x <= xmax; x+= dx) { u = map(x, xmin, xmax, umin, umax); // need better formatting text(String.format("%.0f",x), u, v); } for (float x = -dx; x >= xmin; x-= dx) { u = map(x, xmin, xmax, umin, umax); // need better formatting text(String.format("%.0f",x), u, v); } u = map(0, xmin, xmax, umin, umax); for (float y = dy; y <= ymax; y+= dy) { v = map(y, ymin, ymax, vmin, vmax); // need better formatting text(String.format("%.0f",y), u, v); } for (float y = -dy; y >= ymin; y-= dy) { v = map(y, ymin, ymax, vmin, vmax); // need better formatting text(String.format("%.0f",y), u, v); } } // zoom by a factor of 2 on the point clicked by the user // reduce (xmax-xmin) and (ymax-ymix) by a factor of 2 void mouseClicked() { // (mouseX, mouseY) is in screen (u,v) coordinates // map that to world (x,y) coordinates float x = map(mouseX, umin, umax, xmin, xmax); float y = map(mouseY, vmin, vmax, ymin, ymax); float dx1 = xmax-xmin; // computing the x range float dy1 = ymax-ymin; // comuting the y range float dx2 = dx1/2; // reduce the x range by a factor of 2 float dy2 = dy1/2; // reduce the y range by a factor of 2 xmin = x - dx2/2; xmax = x + dx2/2; ymin = y - dy2/2; ymax = y + dy2/2; redraw(); } void keyPressed() { if (key=='r') { reset(); redraw(); // a processing defined function } if (key == 's') { save("plot.jpg"); } } 

  // YOUR NAME(S) HERE!!!! public static class Polynomial { double[] a; // array of coefficients // default Constructor creates the zero polynomial public Polynomial(){ a = new double; a = 0.0D; } // Constructor based on an array of coefficents public Polynomial(double[] A){ a = new double; // REPLACE a = 0.0D; // REPLACE } // Copy Constructor public Polynomial(Polynomial p){ a = new double; // REPLACE a = 0.0D; // REPLACE } // return ith coefficient (0 returns constant term) public double coeff(int i){ return 0.0; // REPLACE } // returns the degree of this polynomial based on array length // return -1 if p(x)=0 public int degree() { return -12345; // REPLACE } // toString method - works as is! public String toString(){ String s=""; for(int i=a.length-1; i>=0; i--){ s+=a[i]; if (i!=0) s+="x^"+i+" + "; } return s; } // Evaluate this polynomial at x // f(x) = a + a*x + a*x*x + ... // OR // consider using Horner's method: // f(x) = a + x(a + x(a + x(... + x(a[n-1]+ xa[n])...))) public double f(double x){ return 0.0; // REPLACE } // multiply each term of this by the constant -1 // don't change p! public Polynomial negate(){ return new Polynomial(); // REPLACE } // multiply each term of this by the constant b // don't change p! public Polynomial multiply(double b){ return new Polynomial(); // REPLACE } // add two polynomials // don't change p1 or p2! // q(x) = p1(x) + p2(x) // which of p1 and p2 has the smaller degree? public static Polynomial add(Polynomial p1, Polynomial p2){ return new Polynomial(); // REPLACE } // multiply two polynomials (probably hardest) // don't change p1 or p2! // q(x) = p1(x) * p2(x) // Hint: use 2 nested loops public static Polynomial multiply(Polynomial p1, Polynomial p2){ return new Polynomial(); // REPLACE } // Use the power rule to differentiate p(x) // be careful when degree is zero // return q(x) = a + 2*a*x + 3*a*x*x + ... public Polynomial derivative(){ return new Polynomial(); // REPLACE } // Use the power rule to differentiate p(x) // be careful when degree is zero // return L = m*x + b // where m is the derivative evaluated at x // and the line contains the point (x,f(x)) public Line tangent(double x){ return new Line(0, new Point2D(0,0)); // REPLACE } // Use the power rule to integrate p(x), assume constant C is zero public Polynomial integrate(){ return new Polynomial(); // REPLACE } // Integrate this polynomial from x0 to x1 public double integral(double x0, double x1) { Polynomial p = integrate(); // REPLACE return 0.0; // REPLACE } } 

  public static class Line { // the line y=mx+b in the plane // f(x) = mx+b float m; // slope float b; // intercept // send in a slope and intercept public Line(float m$, float b$) { m = m$; b = b$; } // copy constructor public Line(Line L) { m = L.m; b = L.b; } // send in a slope and point public Line(float m$, Point2D p) { m = m$; b = p.y - m*p.x; } // send in a two points public Line(Point2D p1, Point2D p2) { // (p1.y-p2.y)/(p1.x-p2.x) == dy/dx this((p1.y-p2.y)/(p1.x-p2.x), p1); // invoke the slope-point constructor } public String toString() { return "y = " + m + "x + " + b; } public float f(float x) { float y = m*x + b; return y; // return m*x+b; // more compact } // compute the intersection point where this Line intersections L public Point2D intersection(Line L) { if (m==L.m) return null; // lines are parallel and no intersection point exists float x = (L.b-b)/(m-L.m); float y = f(x); return new Point2D(x,y); } public float getSlope() { return m; } public float getYIntercept() { return b; } public float getXIntercept() { return -b/m; } } 

  // a class to represent a point on the plane public static class Point2D { // this is a speacial keyword that refers to this instance // similar to "my name" OR "my address" float x, y; // this.x, this.y // a constructor for the point (x$, y$) public Point2D(float x, float y) { this.x = x; this.y = y; } // a default constructor to construct the point (0,0) public Point2D() { x = 0; y = 0; } // a copy constructor to construct the point identical to p public Point2D(Point2D p) { x = p.x; y = p.y; } // an equals method --- x coordinates are equal and the y coordinates are equal public boolean equals(Point2D p) { //if (x == p.x && y == p.y) return true; //else return false; return x == p.x && y == p.y; } // distance from this point to the origin float distance() { return sqrt(x*x+y*y); } // distance from this point to the point p float distance(Point2D p) { float dx = x-p.x; // this point's x - p's x float dy = y-p.y; // this point's y - p's y return sqrt(dx*dx+dy*dy); } // a toString method is called implicitly when a printable version is needed public String toString() { return "(" + x + "," + y + ")"; } } 

When you are finished, email your lab files to your lab partner and instructor. 