Rational class (scratch).
When using rational classes is not uncommon to have overflows. In this case is interesting to use a Safe int type to catch errors.
You can find a safe int class in:http://safeint.codeplex.com/
// Copyright (C) 2009, Thiago Adams (thiago.adams@gmail.com)
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
template<class T>
T GreatestCommonDivisor(T a, T b)
{
if (a < 0)
a = -a;
if (b < 0)
b = -b;
if (a == 0 && b == 0)
return 0;
T temp;
while (b)
{
temp = b;
b = a % b;
a = temp;
}
return a;
}
template<class T>
class Rational
{
T m_d;
T m_n;
public:
Rational() : m_n(0) , m_d(1) { }
Rational(T n) : m_n(n) , m_d(1) { }
Rational(T n,T d) : m_n(n), m_d(d) { }
Rational& operator = (const Rational& other)
{
m_n = other.N();
m_d = other.D();;
return *this;
}
const T& D() const
{
return m_d;
}
const T& N() const
{
return m_n;
}
const T& Denominator() const
{
return D();
}
const T& Numerator() const
{
return N();
}
T IntegerPart() const
{
return Numerator() / Denominator();
}
T Remain() const
{
return Numerator() % Denominator();
}
bool IsInteger() const
{
return Remain() == 0;
}
void Simplify()
{
T n = GreatestCommonDivisor(Numerator(), Denominator());
if (n != 0)
{
m_n = Numerator() / n;
m_d = Denominator() / n;
}
}
};
typedef Rational<int> RationalInt;
typedef Rational<long long> Rational64;
template<class T>
Rational<T> operator - (const Rational<T>& left, const Rational<T>& other)
{
return Rational<T>(left.N() * other.D() - left.D() * other.N(), left.D() * other.D());
}
template<class T>
Rational<T> operator - (const T& left, const Rational<T>& other)
{
return Rational<T>(left * other.D() - 1 * other.N(), other.D());
}
template<class T>
Rational<T> operator + (const Rational<T>& left,const Rational<T>& other)
{
return Rational<T>(left.N() * other.D() + left.D() * other.N(), left.D() * other.D());
}
template<class T>
Rational<T> operator * (const Rational<T>& left,const Rational<T>& other)
{
return Rational<T>(left.N() * other.N(), left.D() * other.D());
}
template<class T>
Rational<T> operator * (const T& v, const Rational<T>& other)
{
return Rational<T>(v * other.N(), other.D());
}
template<class T>
Rational<T> operator * (const Rational<T>& left,const T& other)
{
return Rational<T>(left.N() * other, left.D());
}
template<class T>
Rational<T> operator / (const Rational<T>& left,const Rational<T>& other)
{
return Rational<T>(left.N() * other.D(), left.D() * other.N());
}
template<class T>
Rational<T> operator / (const Rational<T>& left, const T& v)
{
return Rational<T>(left.N(), left.D() * v);
}
template<class T>
bool operator == (const Rational<T>& left,const Rational<T>& other)
{
return Rational<T>(other - left).N() == 0;
}
template<class T>
bool operator == (const Rational<T>& left,const T& other)
{
return Rational<T>(other - left).N() == 0;
}
template<class T>
bool operator != (const Rational<T>& left,const Rational<T>& other)
{
return !operator ==(other);
}
//Add more operators here...
template<class _Elem, class _Tr, class T>
std::basic_ostream<_Elem, _Tr> &
operator << (std::basic_ostream<_Elem, _Tr> & stream,
const Rational<T> & r)
{
stream << r.Numerator() << (_Elem)'\\' << r.Denominator();
return stream;
}
typedef Rational<int> RationalInt;
typedef Rational<long long> Rational64;
Tests
using namespace UnitTest;
TEST_FUNCTION(Test1)()
{
AreEqual(RationalInt(), 0);
}
TEST_FUNCTION(Test2)()
{
AreEqual(RationalInt(1), 1);
}
TEST_FUNCTION(Test3)()
{
AreEqual(RationalInt(2, 1), RationalInt(10, 5));
}
TEST_FUNCTION(Test4)()
{
RationalInt r1(1, 3);
r1 = r1 + r1 + r1;
RationalInt r2(1);
AreEqual(r1, r2);
}
TEST_FUNCTION(Test5)()
{
RationalInt r1(1, 3);
r1 = r1 + r1 + r1;
RationalInt r2 = r1 / 3;
AreEqual(r2, RationalInt(1, 3));
}
TEST_FUNCTION(Test6)()
{
IsTrue(RationalInt(1).IsInteger());
IsTrue(RationalInt().IsInteger());
IsTrue(RationalInt(3, 1).IsInteger());
}
TEST_FUNCTION(Test7)()
{
RationalInt r1(200);
r1 = r1 / 3;
r1 = r1 * 3;
AreEqual(r1, 200);
}
int main()
{
ConsoleReport rep;
RunAll(rep);
return rep.GetFailedCount();
}