• Java 2 Platform Standard Edition 5.0 API specification
• OpenJDK source code repository for library classes
• Source code from Data structures and problem-solving using Java, third edition
Our goal for today is to design, implement, and test a Fraction
class -- a way to represent exact rational numbers as objects in Java.
BigInteger class
The java.math.BigInteger class
allows programmers to compute with arbitrarily large integer values, as in
Scheme. The limitation is that all of the operations are formulated as
method calls rather than expressions with infix or prefix operators. (For
instance, to compute and print out the sum of three octillion and five
octillion, one might write
BigInteger augend = new BigInteger("3000000000000000000000000000");
BigInteger addend = new BigInteger("5000000000000000000000000000");
System.out.println(augend.add(addend))
a. Look over the documentation for the BigInteger class and acquaint
yourself with the methods for addition, subtraction, negation,
multiplication, and division.
b. Write, compile, and run a test program that 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. (You'll need to
import the BigInteger class from the java.math package.)
Fraction class
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.
a. 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? Justify your answer.
b. Write a two-argument constructor for the Fraction class. It
should take two arguments, each a BigInteger, and store the
arguments in its fields. (Hint: You can invoke a this-constructor
to do the second part of this job.)
c. 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. Note that the
BigInteger constructor needs a String as its argument.
d. 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 b, you'll only have to change one of the constructors.)
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.
a. Revise your constructors 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.
b. 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 BigIntegers.)
The product of two rational numbers a/b and c/d is (ac)/(bd).
a. 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?
The sum of of two rational numbers a/b and c/d is (ad + bc)/(bd).
b. 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.
c. Add a similar subtract method to your Fraction class.
d. Add a negate method that takes no arguments and returns the
negative of the fraction to which the message is sent.
e. 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.
f. 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 concept of
a remainder in this case.
To test these methods, it would be really convenient to have string
representations of Fraction objects that show what their numerators
and denominators are.
a. 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.
b. 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.