#include #include "fraction.h" #include "gcd.h" Fraction::Fraction() : num( 0 ) , den( 0 ) {} Fraction::Fraction( myInt i ) { init( i, 1 ); } Fraction::Fraction( myInt numerator, myInt denominator ) { init( numerator, denominator ); } Fraction Fraction::operator +( Fraction rhs ) { if( NaN() || rhs.NaN() ) { return Fraction(); } if( Inf() ) { if( rhs.NegInf() ) { return Fraction(); } else { return (*this); } } else if( NegInf() ) { if( rhs.Inf() ) { return Fraction(); } else { return (*this); } } myInt d = gcd( den, rhs.den ); return Fraction( num * (rhs.den/d) + rhs.num * (den/d), (den/d) * rhs.den ); } Fraction Fraction::operator -(Fraction rhs) { return (*this) + (-rhs); } Fraction Fraction::operator *( Fraction rhs ) { if( NaN() || rhs.NaN() ) { return Fraction(); } if( Inf() ) { return Fraction( rhs.num, 0 ); } else if( NegInf() ) { return Fraction( -rhs.num, 0 ); } Fraction l( num, rhs.den ); Fraction r( rhs.num, den ); return Fraction( l.num * r.num, l.den * r.den ); } Fraction Fraction::operator /(Fraction rhs) { return (*this) * Fraction( rhs.den, rhs.num ); } Fraction Fraction::operator -() { return Fraction( -num, den ); } bool Fraction::operator ==( Fraction rhs ) { return (num == rhs.num) && (den == rhs.den); } bool Fraction::NaN() { return num == 0 && den == 0; } bool Fraction::Inf() { return num == 1 && den == 0; } bool Fraction::NegInf() { return num == -1 && den == 0; } void Fraction::print( ostream& os ) { if( NaN() ) { os << "NaN"; } else if( Inf() ) { os << "Inf"; } else if( NegInf() ) { os << "NegInf"; } else { os << num; if( den != 1 ) { os << "/" << den; } } } double Fraction::toDouble() { return ratio( num, den ); } ostream& operator<<(ostream& os, Fraction f); // I choose to ignore the case where buf is too short to hold the number. bool Fraction::expand(char buf[], int len) { ostrstream oss( buf, len ); if( NaN() ) { oss << "NaN" << ends; return true; } else if( Inf() ) { oss << "Inf" << ends; return true; } else if( NegInf() ) { oss << "NegInf" << ends; return true; } else if( num == 0 ) { oss << "0" << ends; return true; } myInt a; myInt b; myInt q; myInt r; divide( num, den, q, r ); oss << q; if( r == 0 ) { oss << ends; return true; } oss << "."; a = r * 10; b = den; int rest = len - strlen( buf ); for( int idx = 0; idx < rest; idx++ ) { divide( a, b, q, r ); oss << q; a = r * 10; if( a == 0 ) { break; } } oss << ends; return true; } ostream& operator<<(ostream& os, Fraction f) { f.print(os); return os; } void Fraction::init( myInt numerator, myInt denominator ) { // This is the only place where I check if the numerator and // denominator are within the range of allowable integers for the // myInt type. When myInt is GNU's Integer, they always are. // When myInt is SafeInt, you have to check that they're valid. if( !good( numerator ) || !good( denominator ) ) { num = 0; den = 0; return; } num = numerator; den = denominator; if( den < myInt( 0 ) ) { num = -num; den = -den; } if( den == 0 && num == 0 ) { // It's NaN. stop. } else if( den == 0 ) { // It's infinity. Set numerator to its sign to record // +/- infinity. num = sign( num ); } else if( num == 0 ) { // It's zero. But record plus or minus zero. den = sign( den ); } else { myInt d = gcd( num, den ); num /= d; den /= d; } }