Section 4 - Rational Numbers
5A.4.1 Rational Numbers
Rational numbers are defined to be the set of all numbers of the form:
num/den
where num and den are integers, and den != 0 (num is called the numerator and den is called the denominator).
A single rational number may have many forms, so we define the reduced form to be the one in which the numerator and denominator share no common factors and the denominator is positive.
4/8, 300/600, (-20)/(-40) and 1/2
These are all the same rational number, with 1/2 being the reduced form.
In case a rational number has a reduced form with a 1 in the denominator we normally just write the numerator.
5A.4.2 An Example Using Rational Operators
Let's look at today's example.
#include <iostream> using namespace std; // Rational prototype -------------------------------- class Rational { // friend operators friend Rational operator+(Rational r1, Rational r2); friend Rational operator-(Rational r1, Rational r2); private: long num, den; long gcd(); void reduce(); public: Rational( long n = 0, long d = 1 ); void show(); }; // main method --------------------------------------- int main() { Rational q(-100,-25), r=3, s(-2,5), t(25,-100); Rational ans; ans = q + r; q.show(); cout << "+"; r.show(); cout << " = "; ans.show(); cout << "\n"; ans = s - t; s.show(); cout << "-"; t.show(); cout << " = "; ans.show(); cout << "\n"; ans.show(); cout << "+"; t.show(); cout << " = "; ans = ans + t; ans.show(); cout << "\n"; ans = s + 10; // rational plus int??? s.show(); cout << "+ 10"; cout << " = "; ans.show(); cout << "\n"; return 0; } // Rational method definitions -------------------------- Rational::Rational(long n, long d) { // defaults in case of user error (bad d) num = 0 ; den = 1; if (d == 0) return; // use defaults, above num = n; den = d; reduce(); } long Rational::gcd() // greatest common denominator of num and den { long temp, n, d; for ( n = num, d = den; d != 0; ) { temp = n % d; n = d; d = temp; } return n; } void Rational::reduce() { long gcDiv = gcd(); if (gcDiv) { num /= gcDiv; den /= gcDiv; } if (den < 0) { den = -den; num = -num; } } void Rational::show() { cout << " " << num << "/" << den << " "; } // end Rational method definitions --------------------- // overloaded operator functions --------------------- Rational operator+( Rational r1, Rational r2) { Rational temp; temp.num = r1.num * r2.den + r1.den * r2.num; temp.den = r1.den * r2.den; temp.reduce(); return temp; } Rational operator-( Rational r1, Rational r2) { Rational temp; temp.num = r1.num * r2.den - r1.den * r2.num; temp.den = r1.den * r2.den; temp.reduce(); return temp; }
The output for this program is as follows:

5A.4.3 Observations
There is a question in the source code. We add -2/5 to 10, an int. But we didn't overload the + operator so that it took a Rational and an int. So how did the program know how to get the correct answer? Hint: re-read today's lecture if you don't know!
There are some improvements you could make to this example:
- Make it intelligent enough to know if a 1 is in the denominator, so it writes 4 instead of 4/1.
- Include multiplication and division operators * and /.
- Make the operators members of the class, not external friend functions.
- What else can you think of that would make this a useful class for some mathematician to use?