CS 171 & 171L Introduction to Computer Science I & Lab Fall 2020 

Lab 7: Quadratics

In this lab, you will create a class that allows one to use quadratic functions. You should start off with s1 driving and s2 navigating.

1. Introductions

Introduce yourself to your lab partner. Tell your lab partner about your plans for Spring Break.

Quadratic functions

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

A quadratic function in its simplest form is represented by \[f(x) = ax^2 + bx + c,\] where \(a\), \(b\), and \(c\) are real numbers (in general they can be complex). The graph of \(f\) is a parabola with axis of symmetry at \(x = -b/(2 a)\), vertex at \((-b/(2 a), f(-b/(2 a)))\). It opens up if \(a > 0\), down if \(a < 0\), and is a line if \(a = 0\). The term \(D = b^2 - 4ac\) is called the discriminant and tells us about the roots based on the following three cases:

  1. If \(D>0\), then there are two unequal purely real roots and the parabola crosses the \(x\)-axis. \[r_1 = \underbrace{\dfrac{-b}{2a} + \dfrac{\sqrt{D}}{2a}}_{\text{re part}} + \underbrace{0}_{\text{im part}}i \quad\text{and}\quad r_2 = \underbrace{\dfrac{-b}{2a} - \dfrac{\sqrt{D}}{2a}}_{\text{re part}} + \underbrace{0}_{\text{im part}}i\]
  2. If \(D=0\), then there is one repeated real root because the vertex is on the \(x\)-axis. \[r_1 = r_2 = -b/(2 a) = \underbrace{-b/(2 a)}_{\text{re part}} + \underbrace{0}_{\text{im part}}i.\]
  3. If \(D<0\), then there are two unequal complex roots that are conjugate pairs, and the parabola does not cross or touch the \(x\)-axis. \[r_1 = \underbrace{\dfrac{-b}{2a}}_{\text{re part}} + \underbrace{\dfrac{\sqrt{-D}}{2a}}_{\text{im part}}i \quad\text{and}\quad r_2 = \underbrace{\dfrac{-b}{2a}}_{\text{re part}} + \underbrace{\dfrac{-\sqrt{-D}}{2a}}_{\text{im part}}i\]

Coding

Copy from the file the Lab7.pde into a new Processing window and save this as Lab7. Create a new tab and call it Point2D then copy the code from the Point2D.pde (see below) to that window. Create a new tab and call it Line then copy the code from the Line.pde (see below) to that window. Create a new tab and call it Quadratic then copy the code from the Quadratic.pde (see below) to that window. Create a new tab and call it Complex then copy the code from the Complex.pde (see below), or code from your lab, to that window. Complete the methods in Quadratic.pde, as shown below.


// 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;


Point2D p1, p2;
Line L1, L2, L3, L4, L5;
Quadratic q1, q2;

void setup() {
  size(900, 900);
  reset();
  testing();
  noLoop(); // no animation
}


void testing() {
    System.out.println("- - - - - - - - - - - - - - - - -");
    q1 = new Quadratic(1, -5, 6);
    System.out.println(q1); // 1.0 x^2 + -5.0 x + 6.0 
    System.out.println(q1.concaveUp()); // true
    System.out.println(q1.concaveDown());  // false
    System.out.println(q1.f(0)); // 6
    System.out.println(q1.f(3)); // 0
    System.out.println(q1.f(2)); // 0
    p1 = q1.vertex();
    System.out.println(p1);  // (2.5, -0.25)
    System.out.println(q1.f(q1.vertex().x));  // -0.25
    System.out.println(q1.slope(4));  // 3
    System.out.println(q1.integrate(0,2));  // 4.66666666
    System.out.println(q1.discriminant());  // 1.0
    System.out.println(q1.realRootCount());  // 2
    System.out.println(q1.root1());  // 3.0
    System.out.println(q1.root2());  // 2.0
    L1 = q1.derivative(1);
    System.out.println(L1); // y = -3.0 x + 5.0 
    
    System.out.println("- - - - - - - - - - - - - - - - -");
    
    q2 = new Quadratic(-1,-2,-3);
    System.out.println(q2); // -1.0 x^2 + -2.0 x + -3.0  
    System.out.println(q2.concaveUp()); // false
    System.out.println(q2.concaveDown());  // true
    System.out.println(q2.f(0)); // -3
    System.out.println(q2.f(3)); // -18
    System.out.println(q2.f(2)); // -11
    p2 = q2.vertex();
    System.out.println(p2);  // (2.5, -0.25)
    System.out.println(q2.vertex());  // (-1,-2)
    System.out.println(q2.f(q2.vertex().x));  // -2
    System.out.println(q2.slope(4));  // -10
    System.out.println(q2.integrate(0,2));  // -12.66666666
    System.out.println(q2.discriminant());  // -8
    System.out.println(q2.root1());  // -1.0+1.4142135623730951i
    System.out.println(q2.root2());  // -1.0-1.4142135623730951i
    System.out.println(q1.realRootCount());  // 2
    L2 = q2.derivative(1);
    System.out.println(L2); // y = -4.0 x + -2.0  
}

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);

  //stroke(0, 0, 255);
  //plot(L1);
  //plot(L2);
  //stroke(0, 255, 255);
  //plot(L3);
  //fill(255,0,0);

  stroke(255,0,0);
  plot(q1);
  stroke(0, 255, 0);
  plot(q2);
}

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 plot(Quadratic Q) {
  if (Q == 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) Q.f(x);
    u2 = map(x, xmin, xmax, umin, umax);
    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;
  }
  
  // show roots
  if (Q.realRootCount() == 2) {
    plot(new Point2D((float)(Q.root1().re), 0));
    plot(new Point2D((float)(Q.root2().re), 0));
  }
  else if (Q.realRootCount() == 1) {
    plot(new Point2D((float)(Q.root1().re), 0));
  }
  
  // show vertex
  plot(Q.vertex());
}

  
 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 reset() {
  xmin = -20;
  ymin = -20;
  xmax = 20;
  ymax = 20;
}


void keyPressed() {
  if (key=='r') {
    reset();
    redraw(); // a processing defined function 
  }
  if (key == 's') {
    save("plot.jpg");
  }
}


// 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 + ")";
  }
}


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;
  }
}


public static class Quadratic {
  // three double instance variables representing a, b, and c.
  double a, b, c;
  
  // Constructor that takes three double parameters representing a, b, and c.
  public Quadratic(double a$, double b$, double c$) {
  }
  
  
  // Constructor that copies a Quadratic
  public Quadratic(Quadratic q) {
  }
  
  
  
  // printable form of this quadratic
  public String toString() {
    return "0 x^2 + 0 x + 0";
  }
  
  
  // returns a double representing quadratic function evaluated at x.
  public double f(double x) {
    return 0.0;
  }
  
  
  // returns the discriminant of this quadratic: (b^2 - 4 a c)
  public double discriminant() {
    return 0.0;
  }
  
  
  // returns a boolean that is true if the graph of the quadratic opens up
  public boolean concaveUp() {
    return false;
  }
  
  
  // returns a boolean that is true if the graph of the quadratic opens down
  public boolean concaveDown() {
    return false;
  }
  
  
  // returns an int that represents the number of real roots of this quadratic
  // 0 - both roots are complex when the discriminant is negative
  // 1 - both roots are equal and real when the discriminant is zero
  // 2 - both roots are real an distinct when the discriminant is positive
  public int realRootCount() {
    return 0;
  }
  
  
  // returns a Complex value that represents the first root of the polynomial
  // Hint: Use the discriminant and realRootCount functions
  public Complex root1() {
    return new Complex(0.0D, 0.0D);
  }
  
  
  // returns a Complex value that represents the first root of the polynomial
  // Hint: Use the discriminant and realRootCount functions
  public Complex root2() {
    return new Complex(0.0D, 0.0D);
  }
  
  
  // returns a Point2D representing the vetex of the parabola
  // Recall that the vertex of the parablola is given by (-b/(2a), f(-b/(2a)))
  public Point2D vertex() {
    return new Point2D(0.0, 0.0);
  }
  
  
  // returns a double that is the insantaneous slope of this Quadratic at x: 2 a x + b
  public double slope(double x) {
    return 0.0;
  }
  
  
  // returns a line that represents the derivative of this Quadratic at x
  // 2 a x + b is the slope
  // (x, f(x)) is a point on the line
  // Use point-slope equation to determine the y intercept
  public Line derivative(double x) {
    return new Line(0.0, 0.0);
  }
  
  
  // integral-ish helper method
  // Define F(x) = (a/3)x^3 + (b/2)x^2 + c x 
  double F(double x) {
    return 0.0;
  }
  
  
  // returns a double representing the definite integral from x1 < x2 of this quadratic.
  // intgrate(x1,x2) returns F(x2) - F(x1). 
  public double integrate(double x1, double x2) {
    return 0.0;
  }
}


// Represents a complex number using two doubles, 
// one for the real component and
// one for the imaginary component
public static class Complex {

  double re, im;


  // Create printable format
  // a+bi if b != 0 OR
  // a   if b==0
  public String toString() {
    if (im == 0) 
      return String.format("%f", re);
    if (re == 0) 
      return String.format("%fi", im);
    if (im < 0) 
      return String.format("%f-%fi", re, -im);
    return String.format("%f+%fi", re, im);
  }


  // General constructor creates a+bi
  public Complex(double a, double b) {
    re = a;
    im = b;
  }
}

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


Copyright © 2020, David A. Reimann. All rights reserved.