1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5. namespace NumberAlgorithms
  6. {
  7.     template <class T> T Max(const T& a, const T& b) { return (a > b) ? a : b; }
  8.     template <class T> T Min(const T& a, const T& b) { return (a < b) ? a : b; }
  9.  
  10.     template <class T> T GreatestCommonFactor(const T& a, const T& b)
  11.     {
  12.         T gcf = 1, max = Min(a, b);
  13.         for (T i = 2; i < max; i++)
  14.             if (a % i + b % i == 0)
  15.                 gcf = i;
  16.         return gcf;
  17.     }
  18.     template <class T> T LeastCommonMultiple(const T& a, const T& b)
  19.     {
  20.         T max = a * b;
  21.         for (T i = Min(a, b); i < max; i++;)
  22.             if (i % a + i % b == 0)
  23.                 return i;
  24.     }
  25. };
  26.  
  27. // Fraction SHOULD be a struct, as it is a data type, and doesn't function
  28. // with other objects. Other objects use it, but it doesn't depend on anything.
  29.  
  30. // T must be an number type (representing any real rational number)
  31. template <class T>  // It is not possible to use constraints in c++
  32. class Fraction      // So we have to assume that the user will use an integral type
  33. {
  34. private:
  35.     T Numerator, Denominator;
  36.  
  37.     void Reduce()
  38.     {
  39.         T gcf = NumberAlgorithms::GreatestCommonFactor(Numerator, Denominator);
  40.         Numerator /= gcf;
  41.         Denominator /= gcf;
  42.         if (Denominator < 0)
  43.         {
  44.             Numerator *= -1;
  45.             Denominator *= -1;
  46.         }
  47.     }
  48.  
  49. public:
  50.     Fraction() : Numerator(1), Denominator(1) { }
  51.     Fraction(T n) : Numerator(n) { SetDenominator(1); }
  52.     Fraction(T n, T d) : Numerator(n) { SetDenominator(d); }
  53.  
  54.     void SetNumerator(const T& value)
  55.     {
  56.         Numerator = value;
  57.         Reduce();
  58.     }
  59.     T GetNumerator() const { return Numerator; }
  60.     void SetDenominator(const T& value)
  61.     {
  62.         if (value == 0) throw std::exception("Divide by zero");
  63.         Denominator = value;
  64.         Reduce();
  65.     }
  66.     T GetDenominator() const { return Denominator; }
  67.  
  68.     friend ostream& operator<<(const ostream& output, const Fraction<T> value);
  69.     friend istream& operator>>(const istream& input, Fraction<T> value);
  70.  
  71.     friend Fraction<T> operator+(const Fraction<T>& left, const Fraction<T>& right);
  72.     friend Fraction<T> operator-(const Fraction<T>& left, const Fraction<T>& right);
  73.     friend Fraction<T> operator*(const Fraction<T>& left, const Fraction<T>& right);
  74.     friend Fraction<T> operator/(const Fraction<T>& left, const Fraction<T>& right);
  75.  
  76.     bool operator<(const Fraction<T>& right) const
  77.     {
  78.         T a = GetNumerator(), b = GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator();
  79.  
  80.         return (a * d < b * c);
  81.     }
  82.     bool operator>(const Fraction<T>& right) const
  83.     {
  84.         T a = GetNumerator(), b = GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator();
  85.  
  86.         return (a * d > b * c);
  87.     }
  88.     bool operator<=(const Fraction<T>& right) const
  89.     {
  90.         T a = GetNumerator(), b = GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator();
  91.  
  92.         return (a * d <= b * c);
  93.     }
  94.     bool operator>=(const Fraction<T>& right) const
  95.     {
  96.         T a = GetNumerator(), b = GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator();
  97.  
  98.         return (a * d >= b * c);
  99.     }
  100.     bool operator==(const Fraction<T>& right) const
  101.     {
  102.         T a = GetNumerator(), b = GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator();
  103.  
  104.         return (a * d == b * c);
  105.     }
  106.     bool operator!=(const Fraction<T>& right) const
  107.     {
  108.         T a = GetNumerator(), b = GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator();
  109.  
  110.         return (a * d != b * c);
  111.     }
  112. };
  113.  
  114. template <class T> Fraction<T> operator+(Fraction<T> const& left, Fraction<T> const& right)
  115. {
  116.     T a = left.GetNumerator(), b = left.GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator(), x;
  117.  
  118.     using NumberAlgorithms;
  119.  
  120.     x = LeastCommonMultiple<T>(b, d);
  121.  
  122.     a *= x / d;
  123.     b *= x / d;
  124.     c *= x / b;
  125.     d *= x / b;
  126.  
  127.     return Fraction<T>(a + b, c);
  128. }
  129. template <class T> Fraction<T> operator-(Fraction<T> const& left, Fraction<T> const& right)
  130. {
  131.     T a = left.GetNumerator(), b = left.GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator(), x;
  132.  
  133.     using NumberAlgorithms;
  134.  
  135.     x = LeastCommonMultiple<T>(b, d);
  136.  
  137.     a *= x / d;
  138.     b *= x / d;
  139.     c *= x / b;
  140.     d *= x / b;
  141.  
  142.     return Fraction<T>(a - b, c);
  143. }
  144. template <class T> Fraction<T> operator*(Fraction<T> const& left, Fraction<T> const& right)
  145. {
  146.     T a = left.GetNumerator(), b = left.GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator();
  147.  
  148.     if (b == 0 || d == 0) throw exception("Divide by zero");
  149.  
  150.     return Fraction<T>(a * c, b * d);
  151. }
  152. template <class T> Fraction<T> operator/(Fraction<T> const& left, Fraction<T> const& right)
  153. {
  154.     T a = left.GetNumerator(), b = left.GetDenominator(), c = right.GetNumerator(), d = right.GetDenominator();
  155.  
  156.     if (c == 0 || d == 0) throw new exception("Divide by zero");
  157.  
  158.     return Fraction<T>(a * d, b * c);
  159. }
  160. template <class T> ostream& operator<<(const ostream& output, const Fraction<T>& value)
  161. {
  162.     output << value.Numerator << '/' << value.Denominator;
  163.  
  164.     return output;
  165. }
  166. template <class T> istream& operator>>(const istream& input, Fraction<T>& value)
  167. {
  168.     T n, d, char seperator;
  169.  
  170.     cin >> n >> seperator >> d;
  171.  
  172.     value.SetNumerator(n);
  173.     value.SetDenominator(d);
  174.  
  175.     return input;
  176. }
  177.  
  178. bool Test()
  179. {
  180.     char answer;
  181.     Fraction<int> test1, test2, test3(10);
  182.     int a, b;
  183.  
  184.     cout << endl << "Please enter two whole numbers. ex: a b : ";
  185.     cin >> a >> b;
  186.     test1 = Fraction<int>(a, b);
  187.  
  188.     cout << endl << "Please enter two whole numbers. ex: a/b : ";
  189.     cin >> test2;
  190.  
  191.      // Display the three values to test cout
  192.     cout << "\nTest1 equals " << test1;
  193.     cout << "\nTest2 equals " << test2;
  194.     cout << "\nTest3 equals " << test3;
  195.     // Test our operators
  196.     cout << "\nTest1 * Test2 equals " << test1*test2;
  197.     cout << "\nTest1 / Test3 equals " << test1/test3;
  198.     cout << "\nTest2 + Test3 equals " << test2+test3;
  199.     cout << "\nTest3 - Test1 equals " << test3-test1;
  200.     if (test1 == test2)
  201.         cout << "\nTest1 is equal to Test2";
  202.     if (test1 < test2)
  203.         cout << "\nTest1 is less than Test2";
  204.  
  205.     cout << "Would you like to test again? ";
  206.     cin >> answer;
  207.  
  208.     return answer == 'Y' || answer == 'y';
  209. }
  210.  
  211. int main()
  212. {
  213.     cout << endl << "Project 11-5" << endl << endl
  214.         << "Testing the Fraction class." << endl
  215.         << "The fraction class stores a numerator and denominator digit (n/d)" << endl
  216.         << "Let the testing commence!" << endl;
  217.  
  218.     while (Test()) ;
  219. }