Ian Craw
Sheet 7: Using FormulaeAt the end of this practical, you should be happier programming ``formulae''; for summing series or for finding the roots of a quadratic.
The classes this week are in the package
uk.ac.abdn.maths.mx3015.formulae. You will find a new
directory and some prototype classes in the current version of
mx3015.jar. Start work by extracting it as usual into the
directory mx3015. Here are the commands, assuming you've just
logged in:
bash% cd mx3015 bash% jar xvf f:/data/mx3015/mx3015.jar bash% cd src/uk/ac/abdn/maths/mx3015/formulae
QuadFormula class, which
runs but does not produce sensible answers. Write the
void solve() method which is called during construction, to
store the roots of the quadratic. These should be found using the usual
quadratic formula. Check that the quadratics constructed in the main
method behave as you would expect. Here is the shell of the class; paste it into
your editor to get started.
package uk.ac.abdn.maths.mx3015.formulae;
import java.io.PrintStream;
import java.text.NumberFormat;
/**
* This class instantiates a quadratic written as ax^2 + bx + c.
* This version simply solves using the quadratixc formula, without
* worrying about the loss of precision which may occur when
* subtracting two numbers of a similar size.
*
* @version $Revision: 3.1 $
* @author Your name here!
*/
public class QuadFormula {
/** The coefficient of x^2. */
private double a;
/** The coefficient of x. */
private double b;
/** The constant term. */
private double c;
/** Declare whether we have real or complex roots */
public boolean hasRealRoots;
/**
* The root with the larger modulus - only useful if
* <code>hasRealroots</code> is true.
**/
public double root1;
/**
* The root with the smaller modulus - only useful if
* <code>hasRealroots</code> is true.
**/
public double root2;
/**
* The real part of a pair of complex roots - only useful if
* <code>hasRealroots</code> is false, so the Quadratic has
* complex roots
**/
public double realPart;
/**
* The imaginary part of a pair of complex roots - only useful if
* <code>hasRealroots</code> is false, so the Quadratic has
* complex roots
**/
public double imaginaryPart;
/**
* The constructor is responsible for checking we <em>have</em> a
* quadratic. It initialises the constructor and then calls
* <code>solve</code> which solves the quadratic using the formula
* and sets the roots appropriately.
**/
public QuadFormula (double a, double b, double c) {
if (a == 0) {
throw new IllFormedQuadraticException();
}
this.a = a;
this.b = b;
this.c = c;
solve();
}
/**
* Obtain either two real rools or the real and imaginary parts of
* the two complex roots, necesarily conjugate since the
* coefficients are real. Sets the boolean
* <code>hasRealRoots</code> and <em>exactly</em> two of the four
* instance variables which store the roots.
**/
public void solve() {
double discriminant = b*b - 4*a*c;
//-> You do it.
//<- Finish this way; then test
}
/** A convenience method to display Quadratics. */
public String toString() {
return (a+" x^2 + " + b + " x + " + c);
}
/**
* Purely for testing - print the roots. Note that "System.out"
* is a perfectly sensible PrintStream.
**/
public void printRoots(PrintStream out) {
// The next three lines use more advanced language features.
// to control how much space each entry takes up.
NumberFormat nf = NumberFormat.getInstance();
nf.setMaximumFractionDigits(2);
nf.setMinimumFractionDigits(2);
StringBuffer sb = new StringBuffer();
sb.append("The quadratic " + this) ;
if (hasRealRoots) {
sb.append(" has real roots " + nf.format(root1)
+ " and " + nf.format(root2) + ".");
} else {
sb.append(" has complex roots " + nf.format(realPart)
+ " +/- i " + nf.format(imaginaryPart) + ".");
}
out.println(sb);
}
/** Create some quadratics to test the class. */
public static void main(String argv[]) {
QuadFormula p = new QuadFormula(1.0,5.0,6.0);
p.printRoots(System.out);
p = new QuadFormula(2.0,-4.0,4.0);
p.printRoots(System.out);
p = new QuadFormula(1,-2.0,1.0);
p.printRoots(System.out);
p = new QuadFormula(1.0,10000.0,1.0);
p.printRoots(System.out);
p = new QuadFormula(1.0,-10000.0,1.0);
p.printRoots(System.out);
try{ // This one should fail.
p = new QuadFormula(0.0,-10000.0,1.0);
p.printRoots(System.out);
} catch (Exception e) {
// Just continue
}
}
/** Purpose built exception class just to report the error. **/
class IllFormedQuadraticException extends RuntimeException {
// Just need a constructor.
IllFormedQuadraticException() {
System.out.println("The quadratic term must be non-zero.");
}
}
}
You will also find a
copy in the file QuadFormula.java.in. It is in the updated
distribution; remember to rename the file before starting work.
Quadratic class. Copy your implementation
of the solve() method from the previous question, and modify it
to use the ``product of roots'' method, discussed in (last) Monday's
lecture, to derive the root with the smaller modulus.
Then extend the main method to solve a collection of
quadratics. Their coefficients are specified in a file
quadratics.dat; take the first double on each line to be
the coefficient of
and so on. You are to write the output to
roots.dat. You will need to continually read a line of input,
create the corresponding quadratic and write the roots to the output.
Recall the ideas you practiced in the
uk.ac.abdn.maths.mx3015.files package. Here is the shell of the class; paste it into
your editor to get started.
package uk.ac.abdn.maths.mx3015.formulae;
import java.io.*;
import java.text.NumberFormat;
import java.util.StringTokenizer;
/**
* This class instantiates a quadratic written as ax^2 + bx + c.
*
* @version $Revision: 3.1 $
* @author Your name here!
*/
public class Quadratic {
/** The coefficient of x^2. */
private double a;
/** The coefficient of x. */
private double b;
/** The constant term. */
private double c;
/** Declare whether we have real or complex roots */
public boolean hasRealRoots;
/**
* The root with the larger modulus - only useful if
* <code>hasRealroots</code> is true.
**/
public double root1;
/**
* The root with the smaller modulus - only useful if
* <code>hasRealroots</code> is true.
**/
public double root2;
/**
* The real part of a pair of complex roots - only useful if
* <code>hasRealroots</code> is false, so the Quadratic has
* complex roots
**/
public double realPart;
/**
* The imaginary part of a pair of complex roots - only useful if
* <code>hasRealroots</code> is false, so the Quadratic has
* complex roots
**/
public double imaginaryPart;
/**
* The constructor is responsible for checking we <em>have</em> a
* quadratic. It initialises the constructor and then calls
* <code>solve</code> which solves the quadratic using the formula
* and sets the roots appropriately.
**/
public Quadratic (double a, double b, double c) {
if (a == 0) {
throw new IllFormedQuadraticException();
}
this.a = a;
this.b = b;
this.c = c;
solve();
}
/**
* Obtain either two real rools or the real and imaginary parts of
* the two complex roots, necesarily conjugate since the
* coefficients are real. Sets the boolean
* <code>hasRealRoots</code> and </em>exactly</em> two of the four
* instance variables which store the roots.
**/
public void solve() {
double discriminant = b*b - 4*a*c;
// Code needs writing
//-> You do it.
//<- Finish this way; then test
}
/** A convenience method to display Quadratics. */
public String toString() {
return (a + " x^2 + " + b + " x + " + c);
}
/**
* Purely for testing - print the roots. Note that "System.out"
* is a perfectly sensible PrintStream.
**/
public void printRoots(PrintStream out) {
// The next three lines use more advanced language features.
// to control how much space each entry takes up.
NumberFormat nf = NumberFormat.getInstance();
nf.setMaximumFractionDigits(2);
nf.setMinimumFractionDigits(2);
StringBuffer sb = new StringBuffer();
sb.append("The quadratic " + this) ;
if (hasRealRoots) {
sb.append(" has real roots " + nf.format(root1)
+ " and " + nf.format(root2) + ".");
} else {
sb.append(" has complex roots " + nf.format(realPart)
+ " +/- i " + nf.format(imaginaryPart) + ".");
}
out.println(sb);
}
/** Create some quadratics to test the class. */
public static void main(String argv[]) {
Quadratic p = new Quadratic(1.0,5.0,6.0);
p.printRoots(System.out);
p = new Quadratic(2.0,-4.0,4.0);
p.printRoots(System.out);
p = new Quadratic(1,-2.0,1.0);
p.printRoots(System.out);
p = new Quadratic(1.0,10000.0,1.0);
p.printRoots(System.out);
p = new Quadratic(1.0,-10000.0,1.0);
p.printRoots(System.out);
try{ // This one should fail.
p = new Quadratic(0.0,-10000.0,1.0);
p.printRoots(System.out);
} catch (Exception e) {
// Just continue
}
//-> Finally set up reading and writing to file.
//<- and finish this way
}
/** Purpose built exception class just to report the error. **/
class IllFormedQuadraticException extends RuntimeException {
// Just need a constructor.
IllFormedQuadraticException() {
System.out.println("The quadratic term must be non-zero."); }
}
}
You will also find a
copy in the file Quadratic.java.in. It is in the updated
distribution; remember to rename the file before starting work.
Exp function. Follow the outline discussed
in the lecture. Compare the answers your method gives with those
obtained by the built-in Math.exp(double x) method. Here is the shell of the class; paste it into
your editor to get started.
package uk.ac.abdn.maths.mx3015.formulae;
import uk.ac.abdn.maths.mx3015.util.Evaluable;
/**
* Calculating exp(x) by summing the series.
* @author Your name here!
**/
public class Exp implements Evaluable {
/** Minimal size of term to include in the sum. **/
private double epsilon = 1E-8;
/** No argument constructor picks up the default value of epsilon. **/
Exp() {}
/** Construct with a chosen value of epsilon. **/
Exp(double eps) {
epsilon = eps;
}
/**
* Evaluate exp(x) using the power series. This is where the
* <code> Evaluable</code> interface is implemented.
* @param x the <code>double</code> value at which the
* series should be evaluated.
* @return a <code>double</code> which is the sum of the series.
*/
public double at(double x) {
double sum = 1;
//-> Now you do it.
//<- Finishing this way.
return sum;
}
/** The main method is simply here to test the class. **/
public static void main(String [] argv) {
double value = 1;
Exp exp = new Exp();
System.out.println("We get " + exp.at(value) +
"; the system gets " + Math.exp(value));
exp = new Exp(1.0E-14);
System.out.println("We get " + exp.at(value) +
"; the system gets " + Math.exp(value));
}
}
You will also find a
copy in the file Exp.java.in. It is in the updated
distribution; remember to rename the file before starting work.
ln(1 + x) function, varying the ideas just
used. Compare the answers your method gives with those
obtained by the built-in Math.log(double x) method. Here is the shell of the class; paste it into
your editor to get started.
package uk.ac.abdn.maths.mx3015.formulae;
import uk.ac.abdn.maths.mx3015.util.Evaluable;
/**
* Calculating log(1+x) by summing the series. We use:
* log(1 + x) = x - x^2/s + x^3/3 ..., which is valid for |x| < 1
* @author Your name here!
**/
public class Log implements Evaluable {
/** Minimal size of term to include in the sum. **/
private double epsilon = 1E-8;
/** No argument constructor picks up the default value of epsilon. **/
Log() {}
/** Construct with a chosen value of epsilon. **/
Log(double eps) {
epsilon = eps;
}
/**
* Evaluate log(1+x) using the power series. This is where the
* <code> Evaluable</code> interface is implemented.
* @param x the <code>double</code> value at which the
* series should be evaluated.
* @return a <code>double</code> which is the sum of the series.
*/
public double at(double x) {
double sum = x;
//-> Now you do it.
//<- Finishing this way.
return sum;
}
/** The main method is simply here to test the class. **/
public static void main(String [] argv) {
double value = -0.95;
Log log = new Log();
System.out.println("We get " + log.at(value) +
"; the system gets " + Math.log(1+value));
log = new Log(1.0E-14);
System.out.println("We get " + log.at(value) +
"; the system gets " + Math.log(1+ value));
}
}
You will also find a
copy in the file Log.java.in. It is in the updated
distribution; remember to rename the file before starting work.
Sine function, varying the ideas just used.
If you can, take advantage of the periodicity if Math.floor(double x)
function. Compare the answers your method gives with those obtained
by the built-in Math.sin(double x) method. Here is the shell of the class; paste it into
your editor to get started.
package uk.ac.abdn.maths.mx3015.formulae;
import uk.ac.abdn.maths.mx3015.util.Evaluable;
/**
* Calculating sin(x) by summing the series.
* @author Your name here!
**/
public class Sine implements Evaluable {
/** Calculate, once and for all, a constant we use regularly. **/
static final double twoPi = 2*Math.PI;
/** Minimal size of term to include in the sum. **/
private double epsilon = 1E-8;
/** No argument constructor picks up the default value of epsilon. **/
Sine() {}
/** Construct with a chosen value of epsilon. **/
Sine(double eps) {
epsilon = eps;
}
/**
* Returns the number between -pi and pi which differs from
* <code>x</code> by a multiple of <code>2*Math.PI</code>
* @param x the <code>double</code> which is to be reduced mod 2*PI.
* @return the <code>double</code> reduced value
*/
double reduce(double x) {
//-> There are many ways to do this.
//<- Finish this way. The rest will work anyway.
return x;
}
/**
* Evaluate sin(x) using the power series.
* @param x the <code>double</code> value at which the
* series should be evaluated.
* @return a <code>double</code> which is the sum of the series.
*/
double sumSeries(double x) {
double sum = x;
//-> Your aim is to return the sum of the sine series.
//<- Finishing this way.
return sum;
}
/**
* The <code>at</code> method does the actual evaluation, first
* reducing the argument to lie between -PI and PI before summing
* the series. This is where the <code>Evaluable</code>
* interface is implemented.
*
* @param x the <code>double</code> value at which the
* series should be evaluated.
* @return a <code>double</code> which is the sum of the series.
*/
public double at(double x) {
return (sumSeries(reduce(x)));
}
/** The main method is simply here to test the class. **/
public static void main(String [] argv) {
double angle = Math.PI/4;
Sine sine = new Sine();
System.out.println("We get " + sine.at(angle) +
"; the system gets " + Math.sin(angle));
sine = new Sine(1.0E-14);
System.out.println("We get " + sine.at(angle) +
"; the system gets " + Math.sin(angle));
}
}
You will also find a
copy in the file Sine.java.in. It is in the updated
distribution; remember to rename the file before starting work.
Differentiable interface. Write suitable methods including
ones to add and multiply two polynomials. Although you
will probably find this class is quite like the MathVec class,
note the difference here; that it is perfectly sensible to try to add
two polynomials of different degrees. You will probably find it much
easier to write other methods if you first get accessor and mutator
methods right.
Here is the shell of the class; paste it into
your editor to get started.
package uk.ac.abdn.maths.mx3015.formulae;
import uk.ac.abdn.maths.mx3015.util.*;
import java.io.*;
/**
* A simple implementation of Polynomials.
*
* @author Your name here!
**/
public class Polynomial implements Differentiable {
/** The degree of the polynomial. */
int degree;
/** The actual storage */
private double[] coefficient;
/** It is convenient to allow initialisation from an array */
public Polynomial(double[] newval) {
degree = newval.length -1;
coefficient = new double[degree + 1];
for( int i = 0; i <= degree; i++) {
coefficient[i] = newval[degree-i];
}
}
//-> There are many methods to add.
//<- Remember you must define this
/**
* To implement the Evaluable interface, we must define the "at"
* method which evaluates the polynomial at a given point. Nested
* multiplication significantly reduces the number of operations
* used by writing the polynomial as (...((a_n x + a_{n-1}) x +
* a_{n-2})... ) x + a_0
*/
public double at(double x) {
double result = 0; // initialiser not used
//-> So start work
//<- Finish this way.
return result;
}
//-> Over to you again.
//<- Remember you must define this
/**
* To implement the Differentiable interface, we must define the
* <code> dash </code> method which evaluates the derivative of
* the polynomial at a given point. We've essentially done the
* work already.
**/
public double dash(double x){
double result = 0; // initialiser not used
//-> So start work
//<- Finishing correctly
return result;
}
//-> Again back to you.
// //<-// Uncomment here when you have written the methods
// public String toString() {
// StringBuffer sb = new StringBuffer();
// for (int i = degree; i >0; i--) {
// sb.append(getCoef(i) + "x^" + i + " + ");
// }
// sb.append(getCoef(0));
// return sb.toString();
// }
// //->// This gives a sensible display.
//<- Start testing
/** Create some polynomials to exercise the class. */
public static void main(String argv[]) {
double a[] = {6,5,1};
Polynomial p = new Polynomial(a);
System.out.println("Creating the polynomial p gives: " + p + ".");
double b[] = {1,2,3,4,5};
Polynomial q = new Polynomial(b);
System.out.print("Creating the polynomial q of degree ");
System.out.println( q.degree+ " gives: " + q + ".");
//-> Now add your testing
//<- And finish this way.
}
}
You will also find a
copy in the file Polynomial.java.in. It is in the updated
distribution; remember to rename the file before starting work.
This document was generated using the LaTeX2HTML translator Version 2002-1 (1.67)
Copyright © 1993, 1994, 1995, 1996,
Nikos Drakos,
Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999,
Ross Moore,
Mathematics Department, Macquarie University, Sydney.
The command line arguments were:
latex2html -init_file formulae.l2hinit -debug -verbosity 1 -init_file /home/igc/tools/include/.latex2html-init -t 'MX3015: Mathematical Computation' -up_url ../index/index.html -up_title 'MX3015 Home Page' -split 0 formulae
The translation was initiated by Ian Craw on 2003-12-04