//**************************************************************************// // // // Copyright (c) 1997. // // Richard D. Irwin, Inc. // // // // This software may not be distributed further without permission from // // Richard D. Irwin, Inc. // // // // This software is distributed WITHOUT ANY WARRANTY. No claims are made // // as to its functionality or purpose. // // // // Authors: James P. Cohoon and Jack W. Davidson // // Date: 7/15/96 // // Version: 1.0b // // // // 01/23/97 - Additional comments added by MAR // Overcommented because also explaining the language as well // as the program // 01/28/97 - Added Simplify methods, plus Add and Multiply methods that // use simplify (MAR) // 04/02/98 - Added == operator so that could use function templates in // list.h (it then uses newly added RatsEqual) (MAR) // 12/01/98 - Added many additional functions for arithmetic and comparisons (MAR) //**************************************************************************// #include #include #include "redmo5-rational.h" // default constructor // used if no parameters passed - uses default values - 0/1 Rational::Rational() { SetNumerator(0); SetDenominator(1); } // (numer, denom) constructor // used if 1 or 2 parameters passed - denom defaults to 1 if not specified // (see header) Rational::Rational(int numer, int denom) { SetNumerator(numer); SetDenominator(denom); } // get the numerator int Rational::Numerator() const { return NumeratorValue; } // get the denominator int Rational::Denominator() const { return DenominatorValue; } // set the numerator void Rational::SetNumerator(int numer) { NumeratorValue = numer; } // set the denominator // doesn't allow a zero denominator - uses default of 1 instead void Rational::SetDenominator(int denom) { if (denom != 0) DenominatorValue = denom; else { cerr << "Illegal denominator: " << denom << "using 1" << endl; DenominatorValue = 1; } } // MAR - show value of the rational in its floating point form // float Rational::GetFloating() const { float num = Numerator() * 1.0; float denom = Denominator() * 1.0; float result = num / denom; return result; } // MAR - show value of the rational in its simplified form // simplifying Rationals Rational Rational::GetSimplified() const { Rational result = Simplify(); return result; } // MAR - actually change the objects contents // simplifying Rationals void Rational::SimplifyObj() { //DEBUG clog << " in simplifyobj - obj is: " << this << endl; Rational result = Simplify(); //DEBUG clog << " in simplifyobj - result is: " << result << endl; int numer = result.Numerator(); int denom = result.Denominator(); SetNumerator(numer); SetDenominator(denom); //DEBUG clog << " in simplifyobj - simplified obj is: " << this << endl; } // MAR // simplifying Rationals Rational Rational::Simplify() const { // pull apart numerator and denominators // syntax below uses the function on the current object int numer = Numerator(); int denom = Denominator(); int smaller; int cnt; bool simplified = false; bool found_common_factor = false; // loop until the rational is not simplifiable any more while (!simplified) { //DEBUG clog << "trying to simplify " << Rational(numer,denom) << endl; // use current values for numerator and denominator // wait - service might be desired without changing object // numer = Numerator(); // denom = Denominator(); // check all values up to the smaller of numer and denom // as potential common factors if (numer < denom) { smaller = numer; } else { smaller = denom; } //DEBUG clog << "smaller is: " << smaller << endl; // search until find a common factor or run out of numbers // starting with 2 found_common_factor = false; cnt = 2; while (!found_common_factor && (cnt <= smaller)) { //DEBUG clog << "working with cnt = " << cnt << flush; // if both numerator and denominator are both divisible // by the current number being tried then we have a // common factor if (((numer % cnt) == 0) && ((denom % cnt) == 0) ) { // flag found common factor //DEBUG clog << "common factor found " << cnt << endl; found_common_factor = true; // divide numerator and denominator by common factor numer = numer / cnt; denom = denom / cnt; // wait - service might be desired without changing object // SetNumerator(numer) // SetDenominator(denom) } else { cnt++; } } // if exited loop without finding a common factor then the // rational number is simplified if (!found_common_factor) { simplified = true; } } // construct a new rational and return it return Rational(numer,denom); } // adding Rationals Rational& Rational::AddToMe(const Rational &r) { // do the addition and then assign the result to the current object *this = SimplifyAdd(r); return *this; } // adding Rationals Rational Rational::Add(const Rational &r) const { // pull apart numerator and denominators // syntax below uses the function on the current object int a = Numerator(); int b = Denominator(); // syntax below essentailly specifies the object being used and // the function to use on the object int c = r.Numerator(); int d = r.Denominator(); // construct a new rational and return it return Rational(a*d + b*c, b*d); } // MAR // adding Rationals Rational Rational::SimplifyAdd(const Rational &r) const { // pull apart numerator and denominators // syntax below uses the function on the current object int a = Numerator(); int b = Denominator(); // syntax below essentailly specifies the object being used and // the function to use on the object int c = r.Numerator(); int d = r.Denominator(); //DEBUG clog << " adding " << r << " to " << a << "/" << b << endl; // construct a new rational and return it int newnum = (a*d + b*c); int newdenom = (b*d); //DEBUG clog << " newnum: " << newnum << " newdenom: " << newdenom << endl; Rational result = Rational(newnum,newdenom); //DEBUG clog << " in simplifyadd - addition: " << result << endl; result.SimplifyObj(); //DEBUG clog << " in simplifyadd - simplified: " << result << endl; return result; } // MAR // subtracting Rationals Rational Rational::Subtract(const Rational &r) const { // pull apart numerator and denominators // syntax below uses the function on the current object int a = Numerator(); int b = Denominator(); // syntax below essentailly specifies the object being used and // the function to use on the object int c = r.Numerator(); int d = r.Denominator(); // construct a new rational and return it return Rational(a*d - b*c, b*d); } // MAR // subtracting Rationals Rational Rational::SimplifySubtract(const Rational &r) const { // subtract then simplify // syntax below uses the function on the current object Rational result = Subtract(r); //DEBUG clog << " in simplifysubtract - subtraction: " << result << endl; result.SimplifyObj(); //DEBUG clog << " in simplifysubtract - simplified: " << result << endl; return result; } // multiplying Rationals Rational Rational::Multiply(const Rational &r) const { // pull apart numerator and denominators // syntax below uses the function on the current object int a = Numerator(); int b = Denominator(); // syntax below essentailly specifies the object being used and // the function to use on the object int c = r.Numerator(); int d = r.Denominator(); // construct a new rational and return it return Rational(a*c, b*d); } // MAR // multiplying Rationals Rational Rational::SimplifyMultiply(const Rational &r) const { // pull apart numerator and denominators // syntax below uses the function on the current object int a = Numerator(); int b = Denominator(); // syntax below essentailly specifies the object being used and // the function to use on the object int c = r.Numerator(); int d = r.Denominator(); // construct a new rational and return it Rational result = Rational(a*c, b*d); result.SimplifyObj(); return result; } // dividing Rationals Rational Rational::Divide(const Rational &r) const { // pull apart numerator and denominators // syntax below uses the function on the current object int a = Numerator(); int b = Denominator(); // syntax below essentailly specifies the object being used and // the function to use on the object int c = r.Numerator(); int d = r.Denominator(); // construct a new rational and return it return Rational(a*d, b*c); } // MAR // dividing Rationals Rational Rational::SimplifyDivide(const Rational &r) const { // Divide then simplify // syntax below uses the function on the current object Rational result = Divide(r); //DEBUG clog << " in simplifydivide - division: " << result << endl; result.SimplifyObj(); //DEBUG clog << " in simplifydivide - simplified: " << result << endl; return result; } // inserting a Rational // uses iostream operator << - insertion into a stream // should receive as an argument an iostream object // commonly cout - standard output void Rational::Insert(ostream &sout) const { sout << Numerator() << '/' << Denominator(); return; } // extracting a Rational // uses iostream operator >> - extract from a stream into object(s) // should receive as an argument an iostream object // commonly cin - standard input void Rational::Extract(istream &sin) { int numer; int denom; char slash; // obtain rational number form user - pulling apart into // its components sin >> numer >> slash >> denom; // use mutator functions to update the data members // (the safe way - doesn't depend on implementation) SetNumerator(numer); SetDenominator(denom); return; } // adding Rationals // overloading built-in + so can use same syntax as with ints floats etc // takes two arguments Rational operator+(const Rational &r, const Rational &s) { // sends message to rational object r asking it to add rational // object s to itself // the result is returned to the caller return r.SimplifyAdd(s); } // MAR // adding Rationals updating the first operand // overloading built-in += so can use same syntax as with ints floats etc // takes two arguments // first one is non-const Rational& operator+=(Rational &r, const Rational &s) { // sends message to rational object r asking it to add rational // object s to itself // but assign the result back to r r.AddToMe(s); /* */ // the result is returned to the caller return r; } // multiplying Rationals // overloading built-in + so can use same syntax as with ints floats etc // takes two arguments Rational operator*(const Rational &r, const Rational &s) { // sends message to rational object r asking it to multiply rational // object s with itself // the result is returned to the caller return r.SimplifyMultiply(s); } // MAR // subtracting Rationals // overloading built-in - so can use same syntax as with ints floats etc // takes two arguments Rational operator-(const Rational &r, const Rational &s) { // sends message to rational object r asking it to subtract rational // object s from itself // the result is returned to the caller return r.SimplifySubtract(s); } // dividing Rationals // overloading built-in / so can use same syntax as with ints floats etc // takes two arguments Rational operator/(const Rational &r, const Rational &s) { // sends message to rational object r asking it to divide itself by rational // object s // the result is returned to the caller return r.SimplifyDivide(s); } // comparing Rationals bool operator==(const Rational &r, const Rational &s) { // don't simplify before test - has to be exactly equal return r.Equal(s); } // comparing Rationals bool Rational::RatsEqual(const Rational &s) const { // don't simplify before test - has to be exactly equal int num1 = Numerator(); int num2 = s.Numerator(); int den1 = Denominator(); int den2 = s.Denominator(); // both numerators and denominators must be equal if ((num1 == num2) && (den1 == den2)) { return true; } else { return false; } } // comparing Rationals bool Rational::Equal(const Rational &s) const { // simplify before test - just has to be equivalent Rational one = GetSimplified(); Rational two = s.GetSimplified(); // then compare return one.RatsEqual(two); } // comparing Rationals bool Rational::LessThan(const Rational &s) const { // just compare floating point equivalent values float one = GetFloating(); float two = s.GetFloating(); // then compare return (one < two); } // comparing Rationals bool operator<(const Rational &r, const Rational &s) { // just call the member function return r.LessThan(s); } // comparing Rationals bool operator<=(const Rational &r, const Rational &s) { // use LessThan or Equal return (r.LessThan(s) || r.Equal(s)); } // comparing Rationals bool operator>=(const Rational &r, const Rational &s) { // if it isn't less than - then it is greater or equal return (!r.LessThan(s)); } // comparing Rationals bool operator>(const Rational &r, const Rational &s) { // if it isn't less than and isn't equal then must be greater than return (!r.LessThan(s) && !r.Equal(s)); } // inserting a Rational // overloading built-in << so can use same syntax as with built-in object types ostream& operator<<(ostream &sout, const Rational &r) { // uses member function for the class to actually carry out // the operation // (this overloading is just syntactic sugar (but nice sugar)) // send a message to the rational object telling it to do an insert // into the stream object r.Insert(sout); // return the result so that this insertion can be cascaded // with other insertions in a single expression return sout; } // extracting a Rational // overloading built-in >> so can use same syntax as with built-in object types istream& operator>>(istream &sin, Rational &r) { // uses member function for the class to actually carry out // the operation // (this overloading is just syntactic sugar (but nice sugar)) // send a message to the rational object telling it to do an extraction // from the stream object into itself r.Extract(sin); // return the stream object so that this extraction can be cascaded // with other extractions in a single expression return sin; } // ?? bool operator==(const Rational &r, const Rational &s);