home *** CD-ROM | disk | FTP | other *** search
/ Microsoftware Monthly 19…2 Programming Power Tools / MASO9512.ISO / cpptutor / cpptutor.arj / EXAMPLES / EX0900.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-20  |  4.9 KB  |  119 lines

  1. // \EXAMPLES\EX0900.CPP
  2. //  friends and noninline member functions of Fraction class
  3. //---------------------------------------------------------
  4.  
  5. //  this file is used in the following example programs:
  6. //--------------------------------------------------------------
  7. // %F,15,EX0902.CPP%EX0902.CPP    overloading + - * /
  8. // %F,15,EX0903.CPP%EX0903.CPP    overloading unary + -
  9. // %F,15,EX0904.CPP%EX0904.CPP    overloading binary operators
  10. // %F,15,EX0905.CPP%EX0905.CPP    overloading =
  11. // %F,15,EX0906.CPP%EX0906.CPP    overloading prefix ++ --
  12. // %F,15,EX0907.CPP%EX0907.CPP    overloading postfix ++ --
  13. //---------------------------------------------------------------
  14. // This file must be used with
  15. // %F,15,EX0900.H%EX0900.H      definition of Fraction class
  16. //---------------------------------------------------------------
  17.  
  18. #ifndef FRAC_CPP
  19. #define FRAC_CPP
  20.  
  21. #include <iostream.h>
  22. #include <strstrea.h>        // #include <strstream.h>
  23. #include <limits.h>
  24. #include "EX0900.H"
  25.  
  26. //---------------------------------------------------------
  27. // Constructor - conversion from float or double
  28. //---------------------------------------------------------
  29.  
  30. Fraction::Fraction(double x) : num(0), denom(1)
  31. {
  32.   double y = x < 0 ? -x : x;     // ignore sign if < 0
  33.   int n = int(y);                // set num = whole part
  34.   int d = 1;                     // set denom = 1
  35.   y -= n;                        // set y to fractional part
  36.   int acc = INT_MAX >> 1;        // for largest num & denom
  37.   float dacc = 1.0/INT_MAX;      // to prevent infinite loop
  38.   while ( n < acc && d < acc )   // stop before overflow
  39.   {                              // parse y bit by bit
  40.     n <<= 1; d <<=1;             // left shift num & denom
  41.     y += y;                      // next bit of accuracy in y
  42.     if (y >= 1.0) { n +=1; y -=1; }     // ? update num & denom
  43.     if ( y < dacc ) break;       // stop if residue very small
  44.   };
  45.   if ( x < 0 ) n = -n;           // reinstate sign if < 0
  46.   num = n; denom = d; reduce();  // create the Fraction
  47. }
  48.  
  49. //---------------------------------------------------------
  50. // private member function reduce --> to simlest form
  51. //        --> minus sign in numerator only
  52. //        --> divide by common factors  -- gcd(num,denom)
  53. //---------------------------------------------------------
  54. void
  55. Fraction::reduce()
  56. {
  57.   if ( denom == 0 )                     // if demoninator 0
  58.   {  num = 0; denom = 1; }                 //  set to 0/1
  59.   if ( denom < 0 )                      // if demoninator
  60.   { num = - num; denom = - denom; }        //  move sign to num
  61.   int g = gcd(num, denom);              // find greatest common
  62.   if (g > 1)                               //  denominator
  63.   { num = num/g; denom = denom/g;}      // simplify fraction
  64. }
  65. //---------------------------------------------------------
  66. // Euclid's algorithm for greatest common demoninator
  67. //     the principle: gcd(x,0) = x
  68. //                    gcd(x,y) = gcd(y,x%y)
  69. //          examples: gcd(336,15) = gcd(15,6)
  70. //                                = gcd(6,3)
  71. //                                = gcd(3,0)
  72. //                                = 3
  73. //                       gcd(3,2) = gcd(2,1)
  74. //                                = gcd(1,0)
  75. //                                = 1
  76. //---------------------------------------------------------
  77. // private member function greated common divisor
  78. //---------------------------------------------------------
  79. int
  80. Fraction::gcd(int n, int d)
  81. {
  82.   n = n < 0 ? -n : n;                      // use absolute value
  83.   return n % d == 0 ? d : gcd( d, n % d);  // recursive call gcd
  84. }
  85.  
  86. //---------------------------------------------------------
  87. // overload << operator  -->  ostream << Fraction
  88. //---------------------------------------------------------
  89. ostream&
  90. operator<<( ostream& os, const Fraction& F )
  91. {
  92.    os << F.num << "/" << F.denom;
  93.    return os;
  94. }
  95.  
  96. //---------------------------------------------------------
  97. // overload >> operator  -->  istream >> Fraction
  98. //---------------------------------------------------------
  99. istream&
  100. operator>>( istream& is, Fraction& F)
  101. {
  102.    char c;                            // to hold the '/'
  103.    F.num = 0;                         // default numerator
  104.    F.denom = 1;                       // default denominator
  105.    char buffer[20];                   // for reformatting
  106.    ostrstream oss(buffer,26,ios::out);   // in-memory output
  107.    istrstream iss(buffer,26);            // in-memory input
  108.    char token[20];                    // to hold raw input
  109.    is >> token;                       // read as  string
  110.    oss << token << "/1" << ends;      // write to memory
  111.    iss >> F.num >> c >> F.denom;      // read int-char-int
  112.    if ( c != '/' ) F.denom = 1;       // check syntax n/d
  113.    F.reduce();                        // simplify fraction
  114.    return is;
  115. }
  116. //---------------------------------------------------------
  117.  
  118. #endif
  119.