////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Copyright -C- 1997, by Richard E. Pattis // // Class Name : Rational // // Classification : Class // // Files : Declaration - rational.h // Definition - rational.cpp // // Author : Richard E. Pattis // Computer Science Department // Carnegie Mellon University // 5000 Forbes Avenue // Pittsburgh, PA 15213-3891 // e-mail: pattis@cs.cmu.edu // // Maintainer : Author // // // Description: // // Rational defines a class for rational numbers, representing the ratio of // two integers. The data members of this class are two ints, Numerator and // Denominator. Most of the standard mathematical operators (and many special // C++ operators) are overloaded to work with Rational values. So, if we use // the Rational class, we can perform certain calculations exactly, generating // with no approximation errors. For example, we can compute the harmonic // sequence: 1 + 1/2 + 1/3 +...+ 1/N exactly by using rational arithmetic. // // Because the Rational class is built on ints, it inherits the same problem // as any bounded range type. It is possible to overflow both the numerator and // denominator, invalidating the calculation (and producing strange results: // but sometimes not too strange to notice). // // Note the constructor functions; since each int is also a rational (one // whose denominator is 1) by using a default Denominator argument in the // constructor, we allow C++ to automatically convert an int into a Rational // (but no reverse conversion is allowed). So, if we write 1 + Rational(1,2), // C++ will convert 1 into Rational(1,1) and then apply operator+ - the one // overloaded for two Rational arguments, returning a Rational result. Finally, // the member function Value computes the closest double approximation to the // value of a Rational object by actually dividing the numerator by denominator // (treating both as doubles). // // // Known Bugs : None // // Future Plans : Add self-diagnosing error checking, to throw an exception // if the computed value exceeds int bounds // // History: // 2/ 1/97: R. Pattis - Operational // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // Declarations // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// #ifndef __Rational__ //Do not duplicate in a compilation #define __Rational__ #include //Standard C++ I/O: cin/cout >>/<< //See declaration of >> class Rational { /////// public: /////// //Constructors Rational (); //Default Costructor Rational (int Numerator, int Denominator = 1); Rational (const Rational& R); //Copy Constructor //Assignment Rational& operator= (const Rational& RHS); Rational& operator= (int RHS); //Mutator void Prompt (string Message); //Accessors int Numerator () const; int Denominator () const; double Value () const; //////// private: //////// int my_Numerator; int my_Denominator; }; //Overload Arithmetic Operators Rational operator+ (const Rational& Right); Rational operator- (const Rational& Right); Rational operator+ (const Rational& Left, const Rational& Right); Rational operator- (const Rational& Left, const Rational& Right); Rational operator* (const Rational& Left, const Rational& Right); Rational operator/ (const Rational& Left, const Rational& Right); //Overload Relational Operators: See KLUDGE above bool operator== (const Rational& Left, const Rational& Right); bool operator!= (const Rational& Left, const Rational& Right); bool operator< (const Rational& Left, const Rational& Right); bool operator> (const Rational& Left, const Rational& Right); bool operator<= (const Rational& Left, const Rational& Right); bool operator>= (const Rational& Left, const Rational& Right); //Overload State Change Operators Rational operator+= (Rational& Left, const Rational& Right); Rational operator-= (Rational& Left, const Rational& Right); Rational operator*= (Rational& Left, const Rational& Right); Rational operator/= (Rational& Left, const Rational& Right); //Overload operator not applied primarily to this class // It is primarily applied to ostream class ostream& operator<<(ostream& OS, const Rational& R); #endif ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // Semantics // // // Class Invariants: // my_Numerator is positive or negative // my_Denominator is always positive // The fraction is always stored in lowest common terms: my_Numerator has // no factors in common with my_Denominator // The value 0 is always represented as 0/1 // // // Rational (int Numerator, int Denominator = 1); // PreExc : Denominator != 0; throws invalid_argument // Post : Object constructed with specified Numerator & Denominator // Note : The Denominator parameter has a default value of 1, so // constructing Rational(1) means the same as Rational(1,1) // // // Rational (const Rational& R); // Pre : None // Post : Object is copy of R // // // Rational& operator= (const Rational& RHS); // Pre : None // Post : LHS object is a copy of RHS: the same Numerator and Denominator // // // Rational& operator= (int RHS); // Pre : None // Post : Numerator of LHS value is the same as int RHS, // Denominator of LHS is 1 // // // void Prompt (string Message); // Pre : None // Post : Object stores Numerator and Denominator user enters for prompt // Meaning: The user is prompted with Message, and then two messages: one to // enter the numerator and one to enter the denominator // // // int Numerator (); // Pre : None // Post : Returns object's Numerator // Note : The Numerator can be positive or negative (see invariant above) // This data is stored in a private data member, but is accessible // (but not changable) by calling this member function // // // int Denominator (); // Pre : None // Post : Returns object's Denominator // Note : The Denominator is always positive (see invariant above) // This data is stored in a private data member, but is accessible // (but not changable) by calling this member function // // // double Value (); // Pre : None // Post : Returns object's values, approximated as a double // Note : If a Rational is 1/3, its value would be approximated as the // double .333333333333 // // // Rational operator+ (const Rational& Right); // Pre : None // Post : Returns same value as Right's // // // Rational operator- (const Rational& R); // Pre : None // Post : Returns opposite of Right's // Example: If R = 1/2, -R returns -1/2 // // // Rational operator+ (const Rational& Left, const Rational& Right); // Pre : None // Post : Returns sum of Left and Right // Example: 1/2 + 1/3 returns 5/6 // // // Rational operator- (const Rational& Left, const Rational& Right); // Pre : None // Post : Returns difference of Left and Right // Example: 1/2 - 1/3 returns 1/6 // // // Rational operator* (const Rational& Left, const Rational& Right); // Pre : None // Post : Returns produce of Left and Right // Example: 1/2 * 1/3 returns 1/6 // // // Rational operator/ (const Rational& Left, const Rational& Right); // Pre : None // Post : Returns quotient of Left and Right // Example: 1/2 / 1/3 returns 3/2 // // // bool operator== (const Rational& Left, const Rational& Right); // bool operator!= (const Rational& Left, const Rational& Right); // bool operator< (const Rational& Left, const Rational& Right); // bool operator> (const Rational& Left, const Rational& Right); // bool operator<= (const Rational& Left, const Rational& Right); // bool operator>= (const Rational& Left, const Rational& Right); // Pre : None // Post : Returns standard relational value of Left and Right // Example: 1/2 < 1/3 returns false // // // Rational operator+= (Rational& Left, const Rational& Right); // Rational operator== (Rational& Left, const Rational& Right); // Rational operator*= (Rational& Left, const Rational& Right); // Rational operator/= (Rational& Left, const Rational& Right); // Pre : None // Post : Changes the state of Left to be equal to Right and returns the // value now stored in Left // Example: If R = 1/2; R += 1/3 returns 5/6 after storing 5/6 into R // // // ostream& operator<<(ostream& OS, const Rational& R); // Pre : None // Post : Inserts R's value into output stream OS // Meaning: Assume Rational R(2,3) // cout << R; displays "2/3" on the standard output stream // ////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////