#include <iostream>
using namespace std;
namespace NumberAlgorithms
{
template <class T> T Max(const T& a, const T& b) { return (a > b) ? a : b; }
template <class T> T Min(const T& a, const T& b) { return (a < b) ? a : b; }
template <class T> T GreatestCommonFactor(const T& a, const T& b)
{
T gcf = 1, max = Min(a, b);
for (T i = 2; i < max; i++)
if (a % i + b % i == 0)
gcf = i;
return gcf;
}
template <class T> T LeastCommonMultiple(const T& a, const T& b)
{
T max = a * b;
for (T i = Min(a, b); i < max; i++;)
if (i % a + i % b == 0)
return i;
}
};
// Fraction SHOULD be a struct, as it is a data type, and doesn't function
// with other objects. Other objects use it, but it doesn't depend on anything.
// T must be an number type (representing any real rational number)
template <class T> // It is not possible to use constraints in c++
class Fraction // So we have to assume that the user will use an integral type
{
private:
T Numerator, Denominator;
void Reduce()
{
T gcf = NumberAlgorithms::GreatestCommonFactor(Numerator, Denominator);
Numerator /= gcf;
Denominator /= gcf;
if (Denominator < 0)
{
Numerator *= -1;
Denominator *= -1;
}
}
public:
Fraction() : Numerator(1), Denominator(1) { }
Fraction(T n) : Numerator(n) { SetDenominator(1); }
Fraction(T n, T d) : Numerator(n) { SetDenominator(d); }
void SetNumerator(const T& value)
{
Numerator = value;
Reduce();
}
T GetNumerator() const { return Numerator; }
void SetDenominator(const T& value)
{
if (value == 0) throw std::exception("Divide by zero");
Denominator = value;
Reduce();
}
T GetDenominator() const { return Denominator; }
friend ostream& operator<<(const ostream& output, const Fraction<T> value);
friend istream& operator>>(const istream& input, Fraction<T> value);
friend Fraction<T> operator+(const Fraction<T>& left, const Fraction<T>& right);
friend Fraction<T> operator-(const Fraction<T>& left, const Fraction<T>& right);
friend Fraction<T> operator*(const Fraction<T>& left, const Fraction<T>& right);
friend Fraction<T> operator/(const Fraction<T>& left, const Fraction<T>& right);
bool operator<(const Fraction<T>& right) const
{
T a = GetNumerator(), b = GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator();
return (a * d < b * c);
}
bool operator>(const Fraction<T>& right) const
{
T a = GetNumerator(), b = GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator();
return (a * d > b * c);
}
bool operator<=(const Fraction<T>& right) const
{
T a = GetNumerator(), b = GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator();
return (a * d <= b * c);
}
bool operator>=(const Fraction<T>& right) const
{
T a = GetNumerator(), b = GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator();
return (a * d >= b * c);
}
bool operator==(const Fraction<T>& right) const
{
T a = GetNumerator(), b = GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator();
return (a * d == b * c);
}
bool operator!=(const Fraction<T>& right) const
{
T a = GetNumerator(), b = GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator();
return (a * d != b * c);
}
};
template <class T> Fraction<T> operator+(Fraction<T> const& left, Fraction<T> const& right)
{
T a = left.GetNumerator(), b = left.GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator(), x;
using NumberAlgorithms;
x = LeastCommonMultiple<T>(b, d);
a *= x / d;
b *= x / d;
c *= x / b;
d *= x / b;
return Fraction<T>(a + b, c);
}
template <class T> Fraction<T> operator-(Fraction<T> const& left, Fraction<T> const& right)
{
T a = left.GetNumerator(), b = left.GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator(), x;
using NumberAlgorithms;
x = LeastCommonMultiple<T>(b, d);
a *= x / d;
b *= x / d;
c *= x / b;
d *= x / b;
return Fraction<T>(a - b, c);
}
template <class T> Fraction<T> operator*(Fraction<T> const& left, Fraction<T> const& right)
{
T a = left.GetNumerator(), b = left.GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator();
if (b == 0 || d == 0) throw exception("Divide by zero");
return Fraction<T>(a * c, b * d);
}
template <class T> Fraction<T> operator/(Fraction<T> const& left, Fraction<T> const& right)
{
T a = left.GetNumerator(), b = left.GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator();
if (c == 0 || d == 0) throw new exception("Divide by zero");
return Fraction<T>(a * d, b * c);
}
template <class T> ostream& operator<<(const ostream& output, const Fraction<T>& value)
{
output << value.Numerator << '/' << value.Denominator;
return output;
}
template <class T> istream& operator>>(const istream& input, Fraction<T>& value)
{
T n, d, char seperator;
cin >> n >> seperator >> d;
value.SetNumerator(n);
value.SetDenominator(d);
return input;
}
bool Test()
{
char answer;
Fraction<int> test1, test2, test3(10);
int a, b;
cout << endl << "Please enter two whole numbers. ex: a b : ";
cin >> a >> b;
test1 = Fraction<int>(a, b);
cout << endl << "Please enter two whole numbers. ex: a/b : ";
cin >> test2;
// Display the three values to test cout
cout << "\nTest1 equals " << test1;
cout << "\nTest2 equals " << test2;
cout << "\nTest3 equals " << test3;
// Test our operators
cout << "\nTest1 * Test2 equals " << test1*test2;
cout << "\nTest1 / Test3 equals " << test1/test3;
cout << "\nTest2 + Test3 equals " << test2+test3;
cout << "\nTest3 - Test1 equals " << test3-test1;
if (test1 == test2)
cout << "\nTest1 is equal to Test2";
if (test1 < test2)
cout << "\nTest1 is less than Test2";
cout << "Would you like to test again? ";
cin >> answer;
return answer == 'Y' || answer == 'y';
}
int main()
{
cout << endl << "Project 11-5" << endl << endl
<< "Testing the Fraction class." << endl
<< "The fraction class stores a numerator and denominator digit (n/d)" << endl
<< "Let the testing commence!" << endl;
while (Test()) ;
}