//  File: fraction.C
//  Implementation of the fraction class

#include <iostream.h>
#include <stdlib.h>
#include "fraction.h"

//==========================================================================
// Local functions

static int gcd (int, int) ;

static int gcd (int a, int b) {

    if (b < 0) return gcd(a, -b) ;
    if (a < 0) return gcd(-a, b) ;

    if (b == 0) return a ;

    return gcd(b, a % b) ;
}


//==========================================================================
// Member functions for Fraction class

Fraction::Fraction(int n, int d) {
   int g ;

   // Check for zero denominator
   //
   if (d == 0) {
      cerr << "Fraction: denominator zero!\n" ;
      exit(1) ;
   }

   // Use canonical form for 0
   //
   if (n == 0) {
      numer = 0  ;
      denom = 1 ;
      return ;
   }

   // Only the numerator is negative
   //
   if (d < 0) {
      n = - n ;
      d = - d ;
   }

   // Reduce fraction
   //
   g = gcd(n, d) ;
   if (g != 1) {
      n = n/g ;
      d = d/g ;
   }

   numer = n ;
   denom = d ;
}



// Arithmetic Operators

Fraction Fraction::operator +(const Fraction& b) const {   // addition
   return Fraction(numer * b.denom + b.numer * denom, denom * b.denom) ;
}

Fraction Fraction::operator -(const Fraction& b) const {   // subtraction
   return Fraction(numer * b.denom - b.numer * denom, denom * b.denom) ;
}

Fraction Fraction::operator *(const Fraction& b) const {   // multiplication
   return Fraction(numer * b.numer, denom * b.denom) ;
}

Fraction Fraction::operator /(const Fraction& b) const {   // division
   if (b.numer == 0) {
      cerr << "Division by zero!\n" ;
      exit(1) ;
   }
   return Fraction(numer * b.denom, b.numer * denom) ;
}

Fraction Fraction::operator -() const {                    // unary negation
   return Fraction(-numer, denom) ;
}



// Binary Relational Operators:
//   non-zero return value = YES, zero return value = NO
//
int Fraction::operator <(const Fraction& b) const {
   return numer * b.denom < b.numer * denom ;
}

int Fraction::operator <=(const Fraction& b) const {
   return numer * b.denom <= b.numer * denom ;
}

int Fraction::operator ==(const Fraction& b) const {
   return (numer == b.numer && denom == b.denom) ;
}

int Fraction::operator >=(const Fraction& b) const {
   return numer * b.denom >= b.numer * denom ;
}

int Fraction::operator >(const Fraction& b) const {
   return numer * b.denom > b.numer * denom ;
}



// Test functions
int Fraction::is_zero() const {
   return numer == 0 ;
}

int Fraction::is_one() const {
   return (numer == denom) ;
}

int Fraction::is_int() const {
   return (denom == 1) ;
}



// Conversion
int Fraction::floor() const {
   return numer/denom ;
}

int Fraction::ceiling() const {
   float x ;

   x = ((float) numer)/denom ;
   x += 0.5 ;
   return (int) x ;
}



// Input/Output

void Fraction::display(ostream& out) const {    // show fraction
   out << numer << "/" << denom ;
}



//==========================================================================
// Iostream << and >> operators overloaded (non-member functions)

istream& operator >>(istream& in, Fraction& f) {
   int n, d ;
   char c ;

   // get numerator + one more char
   //
   in >> n >> c ;

   if (c == '/') {
      in >> d ;     // read in denominator
      f = Fraction(n, d) ;
      return in ;
   } else {
      in.clear(ios::badbit | in.rdstate()) ;    // set error state
      return in ;
   }
}

ostream& operator <<(ostream& out, const Fraction& f) {
   f.display(out) ;
   return out ;         // must return output stream
}
