/*
**   rational.h
**
**   This is not offically part of Microway's C++ Runtime Library,
**   Microway owns no Copyright on the following code even though
**   it has been extensively modified by Microway, Inc.
**
**   Rational Number System:
**	examples modified from "An Introduction to Object-Oriented Programming
**      and C++", by Richard S. Wiener and Lewis J. Pinson.
**
**   Microway, Inc. uses its excellent examples as instructional to learning
**   C++ in general.
**
**  			Microway, Inc. 1987 - 1994.
**			P.O. BOX 79
**			Kingston, MA. 02364
**			(508) 746 - 7341 Voice
**			(508) 746 - 4678 FAX
**			e-mail tech@microway.com
*/

#ifndef __RATIONAL_H
#define __RATIONAL_H

#include <stream.h>
#include <stdlib.h>

class rational {
  private:
   void simplify( rational& num );
   long numerator, denominator;

  public:

   // constructor
   rational( long num = 0, long den = 1 ){
      numerator = num;
      denominator = den;
      simplify( *this );
      }

   // Used to assing a rational number a given numerator and denominator
   void assign( long num, long den ) {
      numerator = num;
      denominator = den;
      simplify( *this );
      }

   rational operator= ( rational& num ) {
      numerator = num.numerator;
      denominator = num.denominator;
      simplify( *this );
      return *this;
      }

   rational operator= ( long whole_number ) {
      numerator = whole_number;
      denominator = 1;
      return *this;
      }
   
   rational operator+= ( rational& num ) {
      long old_den = denominator;
      long old_num = numerator;
      long cur_den = num.denominator;
      long cur_num = num.numerator;
      denominator *= cur_den;
      numerator = old_num * cur_den + old_den * cur_num;
      simplify( *this );
      return *this;
      }
   
   rational operator-= ( rational& num ) {
      long old_den = denominator;
      long old_num = numerator;
      long cur_den = num.denominator;
      long cur_num = num.numerator;
      denominator *= cur_den;
      numerator = old_num * cur_den - old_den * cur_num;
      simplify( *this );
      return *this;
      }


   rational operator*= ( rational& num ) {
      numerator *= num.numerator;
      denominator *= num.denominator;
      simplify( *this );
      return *this;
      }

   rational operator/= ( rational &num ) {
      if (num.numerator){
         numerator *= num.denominator;
         denominator *= num.numerator;
         simplify( *this );
         return *this;
         }
      }

   friend rational operator+  ( rational& num1, rational& num2 );
   friend rational operator-  ( rational& num1, rational& num2 );
   friend rational operator*  ( rational& num1, rational& num2 );
   friend rational operator/  ( rational& num1, rational& num2 );
   friend int      operator== ( rational& num1, rational& num2 );
   friend int      operator!= ( rational& num1, rational& num2 );
   friend double real( rational& num );
   friend ostream& operator << ( ostream& s, rational& num );
   };  // end of class rational

// returns a rational number in the simplest form
// i.e. 2/3 == simplify( 20 / 30 )
//

void rational::simplify( rational& num ) {
   int gcd;
   if (num.numerator == 0){
      num.denominator = 1;
      return;
      }

   gcd = ( abs( num.numerator ) > abs( num.denominator ) ?
           abs( num.denominator ) : abs( num.numerator ));

   if (gcd == 0) return;

   do {
      if (gcd == 1) break;
      if ((num.numerator % gcd == 0) && (num.denominator % gcd == 0)) break;
      else --gcd;
      } while (1);  // simulates infinite loop

   num.numerator /= gcd;
   num.denominator /= gcd;
   // attach correct sign to the numerator
   if (num.numerator < 0 && num.denominator < 0){
      num.numerator =- num.numerator;
      num.denominator =- num.denominator;
      }
   else if (num.numerator < 0 || num.denominator < 0){
      num.numerator =- abs(num.numerator);
      num.denominator = abs(num.denominator);
      }
      
   } // end of void rational::simplify

/*
**  Here follows friend functions
*/

   rational operator+ ( rational& num1, rational& num2 ) {
      long dresult = num1.denominator * num2.denominator;
      long nresult = num1.numerator * num2.denominator + 
		      num1.denominator * num2.numerator;
      return rational(nresult,dresult);
      } // end of rational operator+

   rational operator* (rational& num1, rational& num2) {
      long nresult = num1.numerator * num2.numerator;
      long dresult = num1.denominator * num2.denominator;
      return rational( nresult, dresult );
      } //end of rational operator*

   ostream& operator<< ( ostream& s, rational& num ) {
      if (num.denominator != 1)
         return (s << num.numerator << "/" << num.denominator);
      else
         return (s << num.numerator);
      }  // end of ostream& operator<<

   rational operator- ( rational& num1, rational& num2 ){
      long dresult = num1.denominator * num2.denominator;
      long nresult = num1.numerator * num2.denominator -
                     num1.denominator * num2.denominator; 
      return rational( nresult, dresult );
      } // end of rational operator-

   rational operator/ (rational& num1, rational& num2) {
      if (num2.numerator != 0){
         long nresult = num1.numerator * num2.numerator;
         long dresult = num1.denominator * num2.denominator;
         return rational( nresult, dresult );
         }
      } //end of rational operator*

   int operator== ( rational& num1, rational& num2 ) {
      return float(num1.numerator) / float(num1.denominator) ==
             float(num2.numerator) / float(num2.denominator);
      } // end of int operator==

   int operator!= ( rational& num1, rational& num2 ) {
      return float(num1.numerator) / float(num1.denominator) !=
             float(num2.numerator) / float(num2.denominator);
      } // end of int operator!=

   double real( rational& num ) {
      return double(num.numerator) / double(num.denominator);
      }  // end of double real

#endif /* __RATIONAL_H */
