D-Term 2004                               CS 2136                                         Prof. D. Finkel

  

Assignment 3

 

Due Friday, April 23 at 8:50 AM

The Assignment

Create a program in Java which can handle numbers represented in various ways. The idea is that you can create objects which store different kinds of numbers, but manipulate them in uniform ways.

Your program should have the following features:

1)    Define an abstract class called FlexNumber which can hold various kinds of numbers. It should have the following subclasses:

a.    FlexLong: stores the number internally as a long integer.

b.    FlexDouble: stores the number internally as a double-precision floating point number.

c.    FlexComplex: stores the number internally as two double-precision floating-point numbers. These represent the real and imaginary parts of a complex number.

2)    Each class must have methods to do the following things.

a.    Create a number of that type, with a zero default value. This is the default constructor for the class.

b.    Create a number of that type, with appropriate value. This is a non-default constructor.

c.    Copy (duplicate) the object. For compatibility, this must be called clone() and must be declared to return type Object. Of course, it will actually return an object of the same type.

d.    Convert the object into a form suitable for printing (i.e., implement toString() ). It must produce a String in the following formats:

                                       i.    FlexLong: 12345

                                      ii.    FlexDouble: 1234.56 or 1.23456e3    [Don’t worry about controlling the number of decimal places.]

                                     iii.    FlexComplex: { 12345.6 + 789.12i }   [In this example, 12345.6 is the real part, 789.12 is the imaginary part. Don’t forget the curly brackets. Also, there must always be either a plus sign or a minus sign between the real and imaginary parts, never both signs in the same number.]

Note that you can tell the type of a number by the way it prints.

3)    Each class must also have methods to do the following things. These should be defined as abstract methods in the parent class, then implemented as appropriate in each child class. Remember that you cannot create an object of type FlexNumber, because it is an abstract class. But, you can have variables, parameters, and return values of type FlexNumber. This works because of the “isA” rule.

a.    Convert a number of that type to each of the other types (of course, in Java an object cannot change its class, so you will actually have to instantiate a new object of the right type). For example, toFlexDouble() would return an object of type FlexDouble with the equivalent value. If the object is already the correct type, return a duplicate of the object, not a reference to the object itself.

b.    Perform various arithmetic operations. Each of these methods returns a new object of the same type as the original object (not necessarily the same type as the parameter).

                                       i.    Add a number of any type (i.e. FlexNumber or its subclasses) to the object. Call this method addNew().

                                      ii.    Subtract a number of any type from the object. Call this method subtractNew().

                                     iii.    Multiply a number of any type by the object. Call this method multiplyNew().

                                     iv.    Divide a number of any type into the object. Call this method divideNew().

c.    Perform various arithmetic operations. Each of these methods updates the original object, rather than generating a new object. They should all return void.

                                       i.    Add a number of any type to the object. Call this method add().

                                      ii.    Subtract a number of any type from the object. Call this method subtract().

                                     iii.    Multiply a number of any type by the object. Call this method multiply().

                                     iv.    Divide a number of any type into the object. Call this method divide().

4)    There are some design decisions that must be made and whose results must be documented as comments in your code. For now, do something which you think is reasonable; in the next assignment you will have to generate exceptions in some cases:

a.    How should you handle operations where there is loss of accuracy or information, e.g.

                                       i.    conversion of FlexComplex to FlexDouble, if the imaginary part is non-zero.

                                      ii.    conversion of FlexDouble to FlexLong if the fractional part is non-zero.

b.    How should a user of these classes deal with situations which he or she might expect would be equivalent, but are not, for example:

                                       i.    adding a FlexDouble to a FlexLong yields a FlexLong, but adding a FlexLong to a FlexDouble yields a FlexDouble.

                                      ii.    same for FlexDouble and FlexComplex.

5)    Other things:

a.    All data in the subclasses must be private. Provide access methods as necessary for setting and getting the fields. For example, getRealPart() would return the real part of a complex number; setRealPart() would set it. Of course, inside each class the methods can access the data of this object directly. They cannot directly access the data of other objects.

b.    Use the class names specified in this assignment.

c.    For consistency with Java naming conventions, be sure to use the method names clone(), toXXXX()[where XXXX is a class], and getYYYY().

d.    Other method names are suggestions, but use a consistent naming scheme. For example, do not name the method for extracting the real part of a FlexComplex object “getRealPart()”, then name the method for extracting the imaginary part “returnTheImaginaryPartFromAFlexComplex ()”.

e.    Remember, in class FlexNumber, the methods will all be abstract.

f.     There should be one implementation of each method per class. Here’s an example: For each class, you should just need one add() method, with formal parameter type FlexNumber, not separate (overloaded) ones for each subclass. The method knows what class you are in, and it can just use the appropriate conversion and access methods to get the data it needs from the actual argument.

g.    Provide a main program which prints out sample calculations. For testing, you can just make up some examples. For the version you turn in, use the test data listed below. Define the main() method inside class FlexNumber.

h.    Don’t forget Javadoc-compatible comments in the source code. Use summary sentences, @author, @version, @param, and @return.

i.     Provide other appropriate comments inside your code.

j.     This program has no user input, only output.

k.    Remember, anyone can tell the type of a number (e.g. FlexLong, FlexComplex) by looking at its printed format.

l.     Java already has a standard class called Number. FlexNumber is not a subclass of Number.

m.   In case your complex arithmetic is rusty, here is how to multiply two complex numbers. If you have {a+bi} and {c+di}, you multiply them just like you would multiply any other algebraic expression. {a+bi}{c+di} = {ac + adi + bci + bdii} = {ac + (ad+bc)i + bd(-1)} = {(ac-bd) + (ad+bc)i}

n.    To divide complex numbers, multiply the both the numerator and denominator by the complex conjugate of the denominator. The complex conjugate of a number is the number with the same real part but the negative of the imaginary part. So, {a+bi}/{c+di} = ({a+bi}{c-di})/({c+di}{c-di}) . When you multiply out the new numerator you get a complex number. When you multiply out the new denominator, you get a strictly real number (no imaginary part!). It should be easy to divide a complex number by a real number.

What To Turn In

Turn in your .java file using turnin. The program will produce output which indicates it has performed a series of conversions and calculations. Use the sample data listed below.

How to Proceed

For some students, this will be your first Java program of any significance. You should not try to write it by doing this:

1.    Write the code for one class.

2.    Not test it.

3.    Use your editor to copy it for the other classes.

4.    Make the changes you guess are correct for each class.

5.    Compile it for the first time.

6.    Stare in shocked disbelief at the thousands of error messages.

Instead, consider using a sequence like this:

1.    Think about what methods are needed by all the classes. Decide on names for the ones which are not specified.

2.    Decide which methods you want to create first.

3.    Define the parent class and one of the child classes. Create the constructors for this class.

4.    Create and test a main program which creates some numbers.

5.    Define and implement the toString() method for this class.

6.    Modify your main program so it creates and prints some numbers.

7.    Define a second child class.

8.    Add conversion methods for both classes and test them.

9.    Add some of the calculation methods for both classes and test them.

10.  Add the third class.

11.  Add any additional methods needed.

Remember, whenever you write code, compile frequently to catch errors. Execute with sample data and check that the answers match what you expect. Keep backup copies of your source files. Also remember, once you add an abstract method to a class, all its subclasses have to implement that method, or you will not be able to compile.

Sample Data

When we run your program, it should produce output which shows the results for each of these sets of data. Since the program has no user input, you can hard-code the original data into your program.

1)    Convert each of these numbers into each of the types. For each number, print the number and its equivalents on the same line. It would probably be most convenient if you created a method which accepted a FlexNumber, converted it into the three subclasses, and printed out the four numbers. Then you could just call this method with each of the sample numbers.

a.    13579

b.    13579.13

c.    13579.79

d.    1.3579e7

e.    1.3579e25

f.     {135.79+0.0i}

g.    {135.79-5.7i}

For example, sample number “a.” might print as

13579 = 13579   13579.0  {13579.0 + 0.0i}

2)    Perform the following arithmetic operations. For each, perform the calculation twice: Once using the method which produces a new object, and a second time using the method which updates the object. Please print one complete set (the numbers, the operation, and the two results) per line.

a.    Take 135 and add 789 to it.

b.    Take 13.57 and add 45 to it. This should yield a FlexDouble, 58.57 .

c.    Take 45 and add 13.57 to it. This should yield a FlexLong, either 58 or 59 depending on whether you round or truncate.

d.    Take {5.3-1.6i} and multiply it by 5.7 .

e.    Take {5.3-1.6i} and multiply it by {5.7 + 7.3i}

f.      Take {31.89 + 29.57i} and divide it by {5.7 + 7.3i}.