CIT 591 Assignment 7: Fractions
Fall 2009, David Matuszek

Purpose of this assignment

General idea of the assignment

Implement a Fraction API. Write very thorough JUnit tests. Write a small "calculator" program to do arithmetic with fractions.

Create a project named Fraction, and within that, a package named fraction. Your classes, Fraction, FractionTest, and FractionCalculator, will all be within this package.

Declare your class as public class Fraction implements Comparable {...}. (The reason for the "implements" part will be explained in class; for now, just do it.)

The API

Java provides several types of numbers, but it does not provide fractions. Your task is to implement a Fraction API, and write a small program that uses it.

The following table lists some information about your new Fraction type.

Instance variables

Two private integers, known as the numerator and the denominator. Do not provide getters or setters for these instance variables; there is no reason for anything outside the Fraction class to know about them.

Note: Even though these instance variables are private, they are private to the class, not to the object. This means: Any Fraction object can access the private variables of any other Fraction object; it's only outside this class that you cannot access them.

How written n/d, where n is the numerator and d is the denominator.
Restrictions The denominator may not be zero.
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).
• The denominator is never negative. (You can give a negative number for the denominator to the constructor when you create the fraction, but a negative fraction should be represented internally with a negative numerator.)
• Zero should be represented as 0/1.

The following lists the consructors you should have.

Constructor How it uses its parameters
public Fraction(int numerator, int denominator) Parameters are the numerator and the denominator. Normalize the fraction as you create it. For instance, if the parameters are (8, -12), create a Fraction with numerator -2 and denominator 3. The constructor should throw an ArithmeticException if the denominator is zero.
public Fraction(int wholeNumber) The parameter is the numerator and 1 is the implicit denominator.
public Fraction(String fraction)

The parameter is a String containing either a whole number, such as "5" or " -3", or a fraction, such as "8/ -12". Allow blanks around (but not within) integers. The constructor should throw an ArithmeticException if given a string representing a fraction whose denominator is zero.

You may find it helpful to look at the available String methods in the Java API.

Notes:

Method signature What it does
public Fraction add(Fraction f)
Returns a new Fraction that is the sum of this and that:
a/b + c/d is (ad + bc)/bd
public Fraction subtract(Fraction f)
Returns a new Fraction that is the difference of this minus that:
a/b - c/d is (ad - bc)/bd
public Fraction multiply(Fraction f)
Returns a new Fraction that is the product of this and that:
(a/b) * (c/d) is (a*c)/(b*d)
public Fraction divide(Fraction f)
Returns a new Fraction that is the quotient of dividing this by that:
(a/b) / (c/d) is (a*d)/(b*c)
public Fraction abs()
Returns a new Fraction that is the absolute value of this fraction.
public Fraction negate()
Returns a new Fraction that has the same numeric value of this fraction, but the opposite sign.
public Fraction inverse()
The inverse of a/b is b/a.
@Override
public boolean equals(Object o)
Returns true if o is a Fraction equal to this, and false in all other cases.

You need this method for your assertEquals(expectedactual) JUnit tests to work! The assertEquals method calls your equals method to do its testing.
@Override
public int compareTo(Object o)

If o is a Fraction or an int, this method returns:
   • A negative int if this is less than o.
   • Zero if this is equal to o.
   • A positive int if this is greater than o.
If o is neither a Fraction nor an int, this method throws a ClassCastException.

@Override
public String toString()

Returns a String of the form n/d, where n is the numerator and d is the denominator.
   • However, if d is 1, just return n (as a String).
   • The returned String should not contain any blanks.
   • If the fraction represents a negative number, a minus sign should precede the n.
This should be one of the first methods you write, because it will help you in debugging.

Notes:

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

JUnit testing

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.

Most of your tests will have this form:

@Test
public void testAdd() { // Tests that are expected to succeed }

To test for an exception, use this form:

@Test(expected=ArithmeticException.class)
public void testDivideByZero() { // test that should throw an ArithmeticException }
You can find the various kinds of assertions you can make in the JUnit API.

The FractionCalculator

Write a FractionCalculator class (containing a main method) that does calculations with Fractions. The first thing this program does is print a zero (indicating the current contents of the calculator), and a prompt. It then accepts commands from the user, and after each command, prints the result. Here are the commands it should accept:

In each case, the user may enter either a whole number or a fraction for n.

As this class does little computation on its own (it's all done in the Fraction class), and is mostly concerned with input/output, no unit testing is necessary.

You will need to use the Scanner. You can find a brief description in my From Python to Java page, and a much longer description (skip over the confusing details) in the Scanner page in the Java API.

Recommendation: Just use the Scanner's readLine() method, and use String methods to work with the input. Some useful methods are trim(), length(), and substring(beginIndex). I found this somewhat easier that working with the Scanner methods.

Comments

All methods in your Fraction and FractionCalculator class should have Javadoc comments. The methods in your test class do not need to be commented, unless they are particularly complex or non-obvious.

Eclipse can help you by writing the Javadoc "outline" for you, which you can fill in. For example, suppose you have written the method stub (you are using TDD, aren't you?):

    public Fraction add(Fraction f) {
return null;
}

Place your cursor in the method and choose Source -> Generate Block Comment (or hit Ctrl-Alt-J). Eclipse creates the comment

    /**
* @param f
* @return
*/

which you can then fill in, as for example:

    /**
     * Returns the sum of this Fraction and the Fraction f.
* @param f The Fraction to be added to this one.
* @return The sum of the two Fractions.
*/

Grading

Your grade will be based on:

We will use our own programs and our own unit tests for grading purposes--therefore, you must have method names and parameter types exactly as shown.

Due date:

Thursday, October 7 Friday, November 6, before midnight.