Fractions, aka Rational Numbers


Read Problem 9, chap. 6 (p. 380) for the full specification of this assignment

It may come as a bit of a surprise when the C++ floating-point types (float, double), fail to accurately capture a particular value. Certainly double, which is usually stored as a 64-bit value, is far better than the old float, which is only 32 bits, but problems do arise. For example:
float n = 2.0;
float d = 3.0;
cout.precision(17);
cout << n / d << endl;
Produces 0.66666668653488159, which is accurate to 8 decimal places. Not bad, but a bit dirty for a discipline that prides itself on precision.

A solution that is often used when precision is of greatest importance and all of the numbers involved are going to be rational (that is, expressible as a fraction) is to use a custom type that implements fractions / rational numbers. This is what you will do in this assignment.

The spec


Write a C++ program that performs the rational number operations addition, subtraction, multiplication, division, less than, and equals operations on two fractions.
You will have to design a rational number class whose value will be a fraction (e.g. 1/128, or 22/7), with appropriate constructors, accessor and mutator functions. A fraction will be specified as a numerator and a denominator - e.g. the pair (8, 109) represents the fraction 8/109.
Your program must implement the rational number operations listed above, and test both the class and the operations thoroughly.

You need to use constructors for:
    1) correctly initializing member variables, and
    2) creating objects with given initial values.

Note that a fraction may have both a numerator and a denominator, for example: (8/3), or may simply be a number, for example: 6, in which case you will actually use (6/1) to represent it.  Thus, the constructors with two and one arguments should be included in the class definition.
Question: what would be a useful default constructor - i.e. what would you consider to be the null Rational Number?

Your program will have a function for each one of the six operations add, sub, mul, div, less, equals.
For example: Suppose we have defined objects a and b as two fractions, then to compute a + b, we will use:

a.add(b);

When you perform an operation, you do not have to simplify the result, i.e., 4/5 * 5/10 = 20/50.

Here are the rules you will need:

(a/b) + (c/d) = (a*d + b*c) / (b*d)

(a/b) - (c/d) = (a*d - b*c) / (b*d)
(a/b) * (c/d) = (a*c) / (b*d)
(a/b) / (c/d) = (a*d) / (c*b)
(a/b) < (c/d) => (a*d) < (c*b)
(a/b) == (c/d) => (a*d) == (c*b)

Extra credit (1 point)

Extend your class and operator functions to properly handle either positive or negative rational numbers, including the case of both numerator and denominator being negative.