CIT 591 Assignment 6: Fractions and Complex Numbers
Fall 2004, David Matuszek

Purposes of this assignment:

General idea of the assignment:

Implement (1) fractions and (2) complex numbers, as an API. Write very thorough JUnit tests.

Details:

Java provides several types of numbers, but it does not provide fractions or complex numbers. Your task is to implement one of these, and provide tests for the other.

The following table lists the kind of data and the kind of operations you will need.

  Fraction Complex numbers
Components Two integers, known as the numerator and the denominator. Two doubles, known as the real part and the imaginary part.
How written n/d, where n is the numerator and d is the denominator a+bi (or a-bi, if b is negative), where a is the real part and b is the imaginary part; the "i" is a symbol denoting "imaginary"
Restrictions The denominator may not be zero None
Normalization The fraction is always kept in the lowest terms, that is, the Greatest Common Divisor (GCD) of n and d is 1 (use Euclid's algorithm); and
The denominator is never negative
None, really. However, if the imaginary part is negative, it is written as a-bi rather than a+-bi.
Addition a/b + c/d is (ad + bc)/bd a+bi + c+di is (a+c)+(b+d)i
Subtraction a/b - c/d is (ad - bc)/bd a+bi - c+di is (a-c)+(b-d)i
Multiplication (a/b) * (c/d) is (a*c)/(b*d) (a+bi) * (c+di) is (ac-bd)+(ad+bc)i
Division (a/b) / (c/d) is (a*d)/(b*c)

(a+bi) / (c+di) is (ac+bd)/(c2+d2) + (bc-ad)/(c2+d2)i

Absolute Value Assuming that a/b is normalized:
a > 0 ? a / b : -a / b
sqrt(a2+b2) (Same as distance from 0+0i)
Negation -(a/b) is -a/b -(a+bi) is -a-bi
Special Inverse of a/b is b/a Complex conjugate of a+bi is a-bi
Equality If in lowest terms, numerators are equal and denominators are equal Equality of floating point numbers is not well defined--but you can test if two numbers are approximately equal
Greater Than a/b > c/d if ad > bc Can be defined as having the greater distance from 0+0i
Less Than a/b < c/d if c/d > a/b Can be defined as having the lesser distance from 0+0i
Distance Not applicable Distance between a+bi and c+di is sqrt((a-c)2+(b-d)2)+0i
Zero Zero is 0/1 Zero is 0+0i

The Fraction class should have three constructors:

  • One that takes two int parameters, a numerator and a denominator
  • One that takes one int parameter, the numerator (the denominator is assumed to be one)
  • A String such as "5/10", or "2" (allow blanks in the string)

And these public methods:

  • public Fraction add(Fraction f)
  • public Fraction subtract(Fraction f)
  • public Fraction multiply(Fraction f)
  • public Fraction divide(Fraction f)
  • public Fraction abs()
  • public Fraction negate()
  • public Fraction inverse()
  • public boolean equals(Object o)
  • public boolean greaterThan(Fraction f)
  • public boolean lessThan(Fraction f)
  • public String toString()

Fractions should always be kept in a normalized form; normalization should therefore be done by a private method.

The Complex class should have three constructors:

  • One that takes two double parameters, a real part and an imaginary part
  • One that takes one double parameter, the real part (the imaginary part is assumed to be zero)
  • A String such as "3+5i", or "17.5-21.3i", or "3.1416", or "99i" (allow blanks in the string)

And these public methods:

  • public Complex add(Complex c)
  • public Complex subtract(Complex c)
  • public Complex multiply(Complex c)
  • public Complex divide(Complex c)
  • public double abs() // changed return type
  • public Complex negate()
  • public Complex conjugate()
  • public double distance(Complex c) // added
  • public boolean approximatelyEquals(Complex c)
  • public boolean greaterThan(Complex c)
  • public boolean lessThan(Complex c)
  • public String toString()

 

All numbers should be immutable, that is, there should be no way to change their components after the numbers have been created. Most of your methods simply return a new number.

When you override equals from the Object class, notice that it requires an Object as a parameter. This means that the first thing the method should do is make sure that its parameter is in fact a Fraction, and return false if it is not.

To determine whether two complex numbers are approximately equal: Notice that, in some sense, 1234500 and 1234600 are "more equal" than 0.5 and 2.0, because the percentage difference is much greater in the second case. We will therefore define two complex numbers to be "approximately equal" if the distance between them is less than one millionth of the distance of the larger number from zero (0+0i). Change: To simplify testing, you can define "approximately equal" to mean that the distance between two Complex numbers is less that 0.001. This allows you to use the JUnit method assertEquals(expected, actual, 0.001), where expected and actual are doubles.

To put a fraction into its lowest terms, divide both the numerator and the denominator by their Greatest Common Divisor (GCD). Euclid's algorithm finds the GCD of two integers. It works as follows: As long as the two numbers are not equal, replace the larger number with the remainder of dividing the larger by the smaller (that is, larger = larger % smaller). When the two numbers are equal, that value is the GCD. (If this brief explanation isn't enough, look up Euclid's algorithm on the Web.)

You will do this assignment with a partner. One of you should write the Fraction class and the JUnit test for the Complex class; the other should write the Complex class and the JUnit test for the Fraction class. In other words, you each write tests for each other. In a way, this is a sort of competition; you are trying to find more bugs in your partner's class than he/she can find in yours. The desired end result is, of course, that both of you end up bug-free.

For this assignment, you must have a partner. Partners will be assigned as usual, and if for some reason you end up without a partner, it is your responsibility to find one. You can have more than one partner--notice that extra partners will not increase your work load (you still write the same amount of code). If you already have a partner and someone else (doing the opposite kind of number) needs a partner, please oblige if you can.

Every class you write should mention (in the Javadoc comments) that you are the author. In addition, your number class should indicate whose JUnit tests you used, and your JUnit class should indicate who used your tests.

Your goal in writing the number class should be to deal correctly with all possible cases. Throw Exceptions where appropriate--look at the various Exception classes, and use the same kinds of Exceptions as you might get when dealing with ints or doubles. (If you aren't sure what kinds of Exceptions are appropriate, don't ask me about it--experiment with operations on Java's numeric types to see what they do.)

Your goal in writing the JUnit class is to test for every possible error. This includes making sure that the correct Exceptions are thrown when appropriate.

Grading:

Although you work with a partner, you will receive an individual grade. Turn in a zipped file with your number class and your JUnit tests. Do not turn in your partner's classes.

Half of your grade will be based on how correct and complete your number class is, while the other half will be based on how complete and correct your JUnit tests are. We will use our own programs and our own unit tests for grading purposes--therefore, you must have names and parameter types exactly as shown.

Good comments and good indentation and formatting are required, as always.

Due date:

Thursday, October 7, before midnight.