home *** CD-ROM | disk | FTP | other *** search
- // \EXAMPLES\EX0900.CPP
- // friends and noninline member functions of Fraction class
- //---------------------------------------------------------
-
- // this file is used in the following example programs:
- //--------------------------------------------------------------
- // %F,15,EX0902.CPP%EX0902.CPP overloading + - * /
- // %F,15,EX0903.CPP%EX0903.CPP overloading unary + -
- // %F,15,EX0904.CPP%EX0904.CPP overloading binary operators
- // %F,15,EX0905.CPP%EX0905.CPP overloading =
- // %F,15,EX0906.CPP%EX0906.CPP overloading prefix ++ --
- // %F,15,EX0907.CPP%EX0907.CPP overloading postfix ++ --
- //---------------------------------------------------------------
- // This file must be used with
- // %F,15,EX0900.H%EX0900.H definition of Fraction class
- //---------------------------------------------------------------
-
- #ifndef FRAC_CPP
- #define FRAC_CPP
-
- #include <iostream.h>
- #include <strstrea.h> // #include <strstream.h>
- #include <limits.h>
- #include "EX0900.H"
-
- //---------------------------------------------------------
- // Constructor - conversion from float or double
- //---------------------------------------------------------
-
- Fraction::Fraction(double x) : num(0), denom(1)
- {
- double y = x < 0 ? -x : x; // ignore sign if < 0
- int n = int(y); // set num = whole part
- int d = 1; // set denom = 1
- y -= n; // set y to fractional part
- int acc = INT_MAX >> 1; // for largest num & denom
- float dacc = 1.0/INT_MAX; // to prevent infinite loop
- while ( n < acc && d < acc ) // stop before overflow
- { // parse y bit by bit
- n <<= 1; d <<=1; // left shift num & denom
- y += y; // next bit of accuracy in y
- if (y >= 1.0) { n +=1; y -=1; } // ? update num & denom
- if ( y < dacc ) break; // stop if residue very small
- };
- if ( x < 0 ) n = -n; // reinstate sign if < 0
- num = n; denom = d; reduce(); // create the Fraction
- }
-
- //---------------------------------------------------------
- // private member function reduce --> to simlest form
- // --> minus sign in numerator only
- // --> divide by common factors -- gcd(num,denom)
- //---------------------------------------------------------
- void
- Fraction::reduce()
- {
- if ( denom == 0 ) // if demoninator 0
- { num = 0; denom = 1; } // set to 0/1
- if ( denom < 0 ) // if demoninator
- { num = - num; denom = - denom; } // move sign to num
- int g = gcd(num, denom); // find greatest common
- if (g > 1) // denominator
- { num = num/g; denom = denom/g;} // simplify fraction
- }
- //---------------------------------------------------------
- // Euclid's algorithm for greatest common demoninator
- // the principle: gcd(x,0) = x
- // gcd(x,y) = gcd(y,x%y)
- // examples: gcd(336,15) = gcd(15,6)
- // = gcd(6,3)
- // = gcd(3,0)
- // = 3
- // gcd(3,2) = gcd(2,1)
- // = gcd(1,0)
- // = 1
- //---------------------------------------------------------
- // private member function greated common divisor
- //---------------------------------------------------------
- int
- Fraction::gcd(int n, int d)
- {
- n = n < 0 ? -n : n; // use absolute value
- return n % d == 0 ? d : gcd( d, n % d); // recursive call gcd
- }
-
- //---------------------------------------------------------
- // overload << operator --> ostream << Fraction
- //---------------------------------------------------------
- ostream&
- operator<<( ostream& os, const Fraction& F )
- {
- os << F.num << "/" << F.denom;
- return os;
- }
-
- //---------------------------------------------------------
- // overload >> operator --> istream >> Fraction
- //---------------------------------------------------------
- istream&
- operator>>( istream& is, Fraction& F)
- {
- char c; // to hold the '/'
- F.num = 0; // default numerator
- F.denom = 1; // default denominator
- char buffer[20]; // for reformatting
- ostrstream oss(buffer,26,ios::out); // in-memory output
- istrstream iss(buffer,26); // in-memory input
- char token[20]; // to hold raw input
- is >> token; // read as string
- oss << token << "/1" << ends; // write to memory
- iss >> F.num >> c >> F.denom; // read int-char-int
- if ( c != '/' ) F.denom = 1; // check syntax n/d
- F.reduce(); // simplify fraction
- return is;
- }
- //---------------------------------------------------------
-
- #endif
-