Project #4 |
CMSC 131 |
Due Wednesday 3/31 at 11:00PM |
Object-Oriented Programming I |
Type of project: Closed |
Spring 2010 |
Polynomials and Unit Testing
Please review the course policy on open/closed projects before you begin.
Objective
To practice writing a complete Java class, to practice writing and calling methods of all kinds, and to practice writing JUnit tests to make sure your code is implementing the correct tasks.
Introduction
You will write a class that models a second order polynomial (i.e., a trinomial) including support for basic arithmetic including derivatives. The class is "immutable" meaning that once you have made an instance of the polynomial with a specific set of coefficients, it can not be changed (this makes it easier, and more efficient, to implement.) The images below show screenshots of the graphical UI showing some plots of a successfully implemented Polynomial class.
Supplemental Reading
Required reading:
What you Must Implement
You will be writing one class called Polynomial, and you will be adding additional tests to the JUnit tests file. Follow the instructions below very carefully!
IMPORTANT:
If you do not abide by these rules, you will fail many (if not all) of the release tests!
Polynomial class
You must implement all of the data members and methods described below. You may NOT add any instance variables or static variables to this class other than those described below. You may add methods of your own, as long as they are private. Not all of the methods described below are required for drawing the polynomial, but they must all be implemented correctly as part of this assignment. The class you are writing is a very general class that could be of use in a wide variety of projects.
Private Instance Variables
The class will have exactly three instance variables. THESE VARIABLES MUST BE DECLARED PRIVATE AND FINAL! The Polynomial class you are implementing is an immutable class.
- private final MyDouble a;
- private final MyDouble b;
- private final MyDouble c;
These variables represent the coefficients of the Polynomial. That is, your class can represent any polynomial of the form "a*x^2 + b*x + c" given those coefficients. For example, if an instance is supposed to represent the polynomial 17.2x^2 + 3.7x - 5, then the value of a would be 17.2, the value of b would be 3.7, and the value of c would be -5. Note that you don't need to store the strings "x^2" or "x" as part of the state of Polynomial since those are implicitly defined by the semantics of the class. The variables are final because once they are set in the constructors, there is no reason to ever change them. (Instance variables that are final can be initialized from within a constructor, but nowhere else.)
Public Constructors
- A constructor that takes three parameters of type MyDouble representing coefficients a, b, and c (in that order) for the Polynomial being constructed. The data members a, b, and c are to be initialized with these values resulting in the polynomial: "a*x^2 + b*x + c".
- A constructor that takes two parameters of type MyDouble representing coefficients b, and c (in that order) for the Polynomial being constructed. The data member a should be set to 0, and b, and c are to be initialized with the arguments resulting in the polynomial: "b*x + c".
- A constructor that takes one parameter of type MyDouble representing coefficient c for the Polynomial being constructed. The data members a and b should be set to 0, and c is to be initialized with the argument resulting in the polynomial: "c".
- A constructor that takes no parameters for the Polynomial being constructed. The data members a, b, and c should be set to 0 resulting in the polynomial: "0".
- A copy constructor.
Public Instance Methods
- getA -- A simple "getter" for the value of the a data member.
- getB -- A simple "getter" for the value of the b data member.
- getC -- A simple "getter" for the value of the c data member.
- eval -- this method takes one parameter (MyDouble x), evaluates the polynomial at the point represented by the parameter and returns a MyDouble representing the result of that evaluation. I.e., if your polynomial is 1x^2+2x+4, and you call eval(5), it should return 39.
- add -- this method takes one parameter (a Polynomial). It will return a new Polynomial that is equal to the sum of the current object and the parameter. (Do not modify the current object.)
- subtract -- this method takes one parameter (a Polynomial). It will return a Polynomial that is computed by subtracting the value of the parameter from the current object. (Do not modify the current object.)
- limitedMultiply -- this method takes one parameter (a Polynomial). It will return a Polynomial which is the product of the current object and the parameter. But, if the resulting polynomial has a third or fourth order term (terms of the type "x^3" or "x^4"), the method should return null. Note that you can return null by including the statement: "return null;" (Do not modify the current object.) Note that The result of multiplying two polynomials, "ax^2 + bx + c" and "dx^2 + ex + f" is:
(ad)x^4 + (ae + bd)x^3 + (cd + be + af)x^2 + (ce + bf)x + cf
- derivative -- this method takes no parameters and returns a new Polynomial that is computed by taking the derivative of the current object. The formula for the derivative of a polynomial "ax^2 + bx + c" is "2ax + b". (Do not modify the current object.)
- equals -- returns true if all coefficients of the current object are the same as the coefficients of the object that is passed as the parameter (using the MyDouble.equals() method to determine equality of coefficients).
- norm -- this method takes no parameters and returns a new MyDouble object representing the norm of the current object. For this method, use the following definition of norm of a polynomial: sqrt(a^2 + b^2 + c^2).
- compareTo -- this method takes one parameter (a Polynomial) and returns an int. It will compare the norm of the current object with the norm of the parameter. If the norms are equal, this method returns 0; if the norm of the current object is less than the norm of the parameter, this method returns -1; if the norm of the current object is greater than the norm of the parameter, this method returns 1.
- toString -- this method takes no parameters and returns a new String representing the polynomial. The string you create must have exactly the form specified here. See examples below, which illustrate correct return values for the toString() method in each case. Note that you are allowed to use the MyDouble.toString() method for this one method. These are the requirements:
- There are never any spaces in the string.
- Do not include an "*" in the "x^2" and "x" terms. (i.e., create "23x^2", not "23*x^2").
- If there are negative terms, they should be represented by subtraction, not addition of a negative term (i.e., create "2x^2+4x-6", not "2x^2+4x+-6".
- If there are any terms with a 0 coefficient, then skip that term (i.e., create "2x^2-6", not "2x^2+0x-6"). If all 3 coefficients are 0, then the string should be "0"
- If there are any terms with a 1 coefficient, then display that coefficient (i.e., create "2x^2+1x+3", not "2x^2+x+3").
- If the decimal component of a coefficient is 0, then do not include a decimal portion for that coefficient (i.e., create "23x", not "23.0x"). Note that the MyDouble.toString() method does this for you automatically.
- Examples:
- 23.3x^2+37x+8
- -23.3x^2-37x+8
- -23.3x^2-37x+1
- -23.3x^2+1x+8
- 37x+8
- 23.3x^2+8
- 8
- 0
Public Static Methods
- parsePolynomial -- this method takes one parameter (a String) and returns a new Polynomial. The parameter is a String that represents a polynomial of the form similar to that generated by Polynomial.toString(). You must return a new instance of a Polynomial that correctly represents the string. You may assume that the String being passed to this method is correctly formatted. The strings that get passed into this method have the following properties:
- They are completely valid (i.e., there are never any errors that you need to detect)
- Entire terms may be missing, so except for the special case where the entire input is "0", you will never have a zero coefficient (i.e., you will get "2x^2+5", not "2x^2+0x+5").
- If a coefficient is 1, then the actual digit 1 will be always be included. That is, the 1 coefficient will never be skipped.
- There may be any number of spaces at the beginning of the string, at the end of the string, or around the "+" and "-" characters (i.e., between terms), but never within a term. I.e., "2x^2 + 5" or "2x^2 -5" or "2x^2 - 5" are all ok. (This is the one difference between the input to parsePolynomial and the output of toString(), which never has any embedded spaces.)
You will have to use some of the methods in the Java String class, so you should probably review the online documentation for the Java String class. For example, you might want to look at the replaceAll(), lastIndexOf(), charAt() and substring() methods (among others). Also, you might find it useful to use the static method Double.parseDouble() described in the online documentation for the Java Double class. You are not allowed to use the Scanner class for this method.
How to Run the Program
We have provided a class called "PolynomialDriver", which contains a static main method. After you have finished writing the Polynomial class described above, running this main method will display the UI depicted at the beginning of this assignment. Changing the value of any textbox will immediately create and display a polynomial. Note that PolynomialDriver only exercises some of the Polynomial constructors, and the eval() and derviative() methods. The other methods are only exercised by the JUnit tests you write (see below), and the Release tests.
Note that it is possible to get started without writing all of the methods. You can start with just some of the methods (for example, the ones necessary for PolynomialDriver or for the Public tests) by writing "shell methods" for all of the other ones that you later fill in. A shell method is one that has the correct "signature" (that is, return type and parameters), and if it returns something, then return anything of the correct type. I.e., you could write a shell method for add that looks like the following. It will compile, and thus you can run the rest of the program, but of course the add method is not actually adding two polynomials, so any Release tests that use the add method will fail.
// Shell method for "add" that compiles so other methods can be tested
public
Polynomial add(Polynomial poly) {
return
new
Polynomial();
}
JUnit Tests
With this project, we have included some JUnit tests that are "public". The code for these tests has been distributed with the project (see the file PublicTests.java). You can run these tests yourself in Eclipse by opening the file, and from the menu selecting: Run->Run As->JUnit Test.
You must write additional JUnit tests that you place in the PublicTests.java file that will determine if each of the methods you implemented (as required above) are correct. The tests that should be included are for the 12 public methods (except for "eval()" which is already tested in the version of PublicTests.java distributed to you), and 1 static method. These 12 JUnit tests (11 instance and one static method - remember, you don't need to test eval()) need to fully test the methods of the Polynomial class that you are writing. They should test a variety of different situations. You may add additional methods if you would like. Make sure you are testing more than one set of values for each of the methods - one test case is not usually enough to determine if it works correctly. Look for as much variety as possible in your test cases to ensure a higher level of confidence that your code works as described.
Your JUnit tests must include a comment before each method specifying what is being tested.
Requirements
Grading
Your grade will be determined as follows: