Laboratory: Rational Numbers
 CSC 207 Algorithms and Object Oriented Design Spring 2011

Summary: In this lab, you will write and experiment with objects of your first class. Our goal is to design, implement, and test a `Fraction` class -- a way to represent exact rational numbers as objects in Java.

# Preparation

1. Make a directory for the files you'll create in this lab.
`  mkdir somewhere/objects`
2. Go to your new directory.
` cd somewhere/objects`
3. Copy an example class to your current directory
` cp ~weinman/public_html/courses/CSC207/2011S/labs/code/objects/TestBigInteger.java .`

# Exercises

## Exercise 1

The `java.math.BigInteger` class allows programmers to compute with arbitrarily large integer values. The limitation is that all of the operations are formulated as method calls rather than expressions with infix or prefix operators. For instance, the program `TestBigInteger`, which you copied in the preparations, computes and prints out the sum of three octillion and five octillion.

TestBigInteger.java
``````import java.math.BigInteger;

/** Demonstration of BigInteger objects
*
* @author John David Stone
* @author Jerod Weinman
*/
public class TestBigInteger
{
public static void main(String[] args)
{
BigInteger augend = new BigInteger("3000000000000000000000000000");

System.out.println(sum);
}

}``````
1. Look over the documentation for the `BigInteger` class and acquaint yourself with the methods for addition, subtraction, negation, multiplication, and division.
2. Modify the class `TestBigInteger` so that it also prints out the quotient and the remainder when the product of seven trillion and ninety-six trillion is divided by seventeen million three hundred and nineteen.

## Exercise 2

To represent a rational number, we can use an object that has two fields, each holding a `BigInteger` value. One of these fields will be the numerator of a fraction expressing the rational number and the other will be the denominator.
1. In a file called `Fraction.java`, write the definition for a class that has two `BigInteger` fields called `numerator` and `denominator`. Should these fields be static? What visibility should they have? Justify your answers.
2. Write a two-argument constructor for the `Fraction` class. It should take two arguments, each a `BigInteger`, and store the arguments in the appropriate fields.
3. Write a second two-argument constructor for the `Fraction` class. It should take two arguments, each an `int`. From each argument, the constructor should then build a `BigInteger` with the same value and store that `BigInteger` into the corresponding field.

(Hint: Invoke a `this`-constructor to make the code very short.)

Note that the `BigInteger` constructor needs a `String` as its argument. That's actually a pretty inefficient way to get a `BigInteger` object. Examine the class methods (`static`) of `BigInteger` for a better way.

4. Revise your constructors so that it throws an `ArithmeticException` (which is an unchecked exception type) when an attempt is made to construct a `Fraction` in which the denominator is zero. (If you followed the hint in part c, you'll only have to change one of the constructors.)

## Exercise 3

Let's establish some invariants for our rational numbers. These are conditions that, though perhaps not logically necessary, are conveniently enforced as conventions of our representation and will simplify some of the coding later on.

For instance, in ordinary arithmetic, fractions are usually represented as having only positive numbers as denominators; when, in our computations, we find a negative number in the denominator, we reverse its sign and the sign of the numerator in presenting our result. For instance, we write "-3/5" rather than "3/-5", even though theoretically these express the same rational number. Similarly, we'd always write "5/7" rather than "-5/-7".

Similarly, fractions are usually expressed "in lowest terms" -- any divisors common to the numerator and denominator are cancelled in the final form. For instance, we'd write "2/5" rather than "24/60". That is to say, we divide both the numerator and the denominator by their greatest common divisor, in this case 12, to express the fraction in lowest terms.

1. Revise your constructor(s) so that, if the proposed denominator is negative, both the proposed numerator and the proposed denominator are negated before they are stored the corresponding fields.
2. Revise your constructors so that the fraction is stored in lowest terms, with the numerator and the denominator having no common divisors greater than 1. (Hint: The `BigInteger` class supports a method that computes the greatest common divisor of two `BigInteger`s.)

## Exercise 4

1. The product of two rational numbers a/b and c/d is (ac)/(bd). Add a `multiply` method to your `Fraction` class that takes a `Fraction` as argument and multiplies the fraction to which the message is sent by the fraction supplied as argument, returning the product (as a `Fraction`, of course). Will the product that you return always be expressed in lowest terms?
2. The sum of of two rational numbers a/b and c/d is (ad + bc)/(bd). Add an `add` method to your `Fraction` class that takes a `Fraction` as argument and adds it to the fraction to which the message is sent, returning the sum as a `Fraction`.
3. Add a similar `subtract` method to your `Fraction` class.
4. Add a `negate` method that takes no arguments and returns the negative of the fraction to which the message is sent.
5. Add a `reciprocal` method that takes no arguments and returns the reciprocal of the fraction to which the message is sent (i.e., a new fraction with the numerator and denominator swapped). Ensure that your method throws an `ArithmeticException` if it is sent to a fraction in which the numerator is zero.
6. Add a similar `quotient` method to your `Fraction` class, throwing an `ArithmeticException` if the numerator of the divisor is zero. Note that the quotient of any two non-zero rational numbers can always be expressed exactly as a rational number, so there is no need of a remainder in this case.

## Exercise 5

To test these methods, it would be really convenient to have string representations of `Fraction` objects that show what their numerators and denominators are.
1. Add a `toString` method to your `Fraction` class that takes no arguments and returns a string formed by concatenating the string representation of the numerator, a slash character, and the string representation of the denominator.
2. Test your work by writing a `main` method that constructs some fractions, prints out their string representations, performs some arithmetic on them, and prints out the results.
Created: John David Stone, 8 February 2008
Revised: Jerod Weinman, 4 February 2011