Rational Number Class

Objectives

  • Create a class (Rational) conforming to an API (Rational.h, Number.h).
  • Create a sublass (Rational is a subclass of Number).
  • Use a templated class (Number).
  • Initialize and use a static variable within a class (display_style).
  • Create constructors, including a copy constructor.
  • Create a common initialization function for the constructors to use.
  • Create accessor methods.
  • Overload unary and binary operators.
  • Overload the insertion and extraction operators using friend functions.
  • Use exceptions to indicate errors.

Overview

Rational numbers are numbers which can be represented as fractions. They have an integer numerator and denominator, where the denominator is not allowed to be 0. You are given a base class (superclass) which your Rational class will be based on. You are given the header file for the class you are writing. You are also given the code for a testing program which should produce the sample output included later in this page.

This is a large and complex assignment - but a lot of it is repetitive. We will be doing a few small pieces of the implementation during classroom demonstration of some of these concepts. I would suggest you make good friends with someone in the class if you miss that class session so you can get the notes/code. If you find that any one of the functions you are writing gets to ten lines in length, then please ask for assistance. Most of the functions should be one to three lines of code within their function body. A few functions (gcd(int,int), setNums(int,int), operator<<, operator>>) will probably be five to eight lines of code.

Resources

Assignment requirements

  1. The only file you should be modifying is Rational.cpp
  2. Add documentation comments to Rational.cpp
  3. The starting files will be made available on the server we are using in the ~dklick/examples/cis250/rational directory.
  4. Some of the functions in Rational.cpp may already be completed for you. You're welcome. There is also a Complex number class demonstration in the CIS 250 demonstration programs list which may be helpful.
  5. The display_style variable should be initialized to Rational::FRACTIONAL. This is a static variable, so it must be initialized separately. You will have to use the Rational:: scope resolution more than once in this statement.
  6. There must be a function setDisplayStyle(DisplayStyle) which sets the static display_style variable to the value passed to it.
  7. There should be a private init function which takes two int values and sets the numerator and denominator from those values. It must do error checking and simplification. That is what the setNums(int, int) function is for. All of the constructors should use the init(int, int) function.
  8. There should be a default constructor that sets both the numerator and denominator to 1. Use the init(int,int) function.
  9. There should be a constructor that takes two int values and sets the numerator and denominator to those values. Use the init(int,int) function.
  10. There should be a copy constructor that sets the numerator and denominator to the value of the object passed in. Use the init(int,int) function.
  11. Whenever the numerator and denominator are set, several error checks and a simplification must be done. That's what the setNums(int,int) function is for. The init(int,int) function should use setNums(int,int) since it is available.
  12. The setNums(int,int) function must do the following:
    1. If the denominator is 0, then throw an invalid_argument exception with the message, "Invalid rational number: n/d" (where n and d are replaced by the numerator and denominator). The invalid_argument class is in the stdexcept library. You can use a char array and sprintf (just kidding... use a stringstream) to create the error message.
    2. Set the object's numerator and denominator from the suggested values.
    3. If the numerator is 0, then make the denominator 1.
    4. If the requested denominator is negative, reverse the sign of both the requested numerator and requested denominator.
    5. Call the simplify() function.
  13. The simplify() function just has to divide the numerator and denominator by their greatest common divisor.
  14. Here's a recursive greatest common divisor function you can use:
  15. Create two accessor methods: getNumerator() and getDenominator()
  16. Overload the addition operator. It should return a new Rational object with the appropriate numerator and denominator. Addition is defined as follows: a/b + c/d ==> (a*d + c*b)/(b*d)
  17. Overload the subtraction operator. It should return a new Rational object with the appropriate numerator and denominator. Subtraction is defined as follows: a/b - c/d ==> (a*d - c*b)/(b*d)
  18. Overload the multiplication operator. It should return a new Rational object with the appropriate numerator and denominator. Multiplication is defined as follows: a/b * c/d ==> (a*c)/(b*d)
  19. Overload the division operator. It should return a new Rational object with the appropriate numerator and denominator. Division is defined as follows: a/b / c/d ==> (a*d)/(c*b)
  20. It should be noted that we have ignored what happens with division when the second Rational number is 0. In a full implementation, we would expect to throw an exception.
  21. Overload the assignment (=) operator and the following compound assignment operators: +=, -=, *=, /=
  22. Overload the relational operators: = =, !=, <, <=, >, >=
  23. Overload the pre and post versions of the increment (++) and decrement (--) operators.
  24. The extraction operator (input) should ask for a numerator and denominator and set the object passed in appropriately using setNums(int,int).
  25. The insertion operator (output) should display the Rational number in fractional form if the display_style variable is set to FRACTIONAL, but in floating point form if the display_style variable is set to FLOATING_POINT.
  26. It should be fairly obvious what the other functions specified in the header file are supposed to do.

Grading rubric

Note: Program must be able to be compiled and run to get any points.

  • 2 pts: display_style variable initialized properly
  • 4 pts: simplify() works properly
  • 2 pts: init(const int, const int) works properly
  • 2 pts Rational() works properly
  • 2 pts: Rational(const Rational&) works properly
  • 2 pts: Rational(const int, const int) works properly
  • 7 pts: setNums(const int, const int) works properly
  • 1 pt: getNumerator() works properly
  • 1 pt: getDenominator() works properly
  • 2 pts: setDisplayStyle(const Rational::DISPLAY) works properly
  • 2 pts: operator-=(const Rational&) works properly
  • 2 pts: operator/=(const Rational&) works properly
  • 2 pts: operator-(const Rational&) works properly
  • 2 pts: operator/(const Rational&) works properly
  • 2 pts: operator!=(const Rational&) works properly
  • 2 pts: operator<=(const Rational&) works properly
  • 2 pts: operator>(const Rational&) works properly
  • 2 pts: operator>=(const Rational&) works properly
  • 2 pts: operator--() works properly
  • 2 pts: operator--(int) works properly
  • 5 pts: operator<<(ostream&, const Rational&) works properly

Sample output