fork download
  1. // Little exercice: implementation of a rational class.
  2. // Implemented in C++11
  3. // (c) Luc Hermitte, 2013, under Boost SoftWare Licence.
  4. #include <cmath>
  5. #include <cassert>
  6. #include <ostream>
  7.  
  8. template <typename Int> Int pgcd(Int a, Int b) {
  9. while (a != 0) {
  10. b %= a;
  11. if (b == 0) return a;
  12. a%= b;
  13. }
  14. return b;
  15. }
  16.  
  17. /** Helper class to check invariants.
  18.  */
  19. template <typename CheckedClass>
  20. struct InvariantChecker {
  21. InvariantChecker(CheckedClass const& cc_) : m_cc(cc_)
  22. { m_cc.check_invariants(); }
  23. ~InvariantChecker()
  24. { m_cc.check_invariants(); }
  25. private:
  26. CheckedClass const& m_cc;
  27. };
  28.  
  29. /**rational class.
  30.  * @invariant <tt>denominator() > 0</tt>
  31.  * @invariant visible objects are normalized.
  32.  * @note not optimized.
  33.  */
  34. struct rational
  35. {
  36. typedef long long int_type;
  37. rational(int_type num_=0, int_type den_=1)
  38. : rational(num_, den_, no_normalize{})
  39. {
  40. normalize();
  41. check_invariants();
  42. }
  43. int_type numerator() const { return m_numerator;}
  44. int_type denominator() const { return m_denominator;}
  45.  
  46. /**
  47.   *@pre <tt>m_numerator *rhs_.denominator() < std::numeric_limit<int_type>::max()</tt>, unchecked
  48.   *@pre <tt>m_denominator * rhs_.numerator() < std::numeric_limit<int_type>::max()</tt>, unchecked
  49.   *@pre <tt>lhs_.n * rhs_.d + lhs_.d * rhs_.n < std::numeric_limit<int_type>::max()</tt>, unchecked
  50.   */
  51. rational& operator+=(rational const& rhs_) {
  52. InvariantChecker<rational> check(*this);
  53. m_numerator = m_numerator *rhs_.denominator() + m_denominator * rhs_.numerator();
  54. m_denominator *= rhs_.denominator();
  55. normalize();
  56. return *this;
  57. }
  58. rational& operator-=(rational const& rhs_) {
  59. InvariantChecker<rational> check(*this);
  60. return (*this) += - rhs_;
  61. }
  62. rational& operator*=(rational const& rhs_) {
  63. InvariantChecker<rational> check(*this);
  64. m_numerator *= rhs_.numerator();
  65. m_denominator *= rhs_.denominator();
  66. normalize();
  67. return *this;
  68. }
  69. /**
  70.   *@pre <tt>rhs_ != 0</tt>
  71.   */
  72. rational& operator/=(rational const& rhs_) ;
  73. rational operator-() const {
  74. return rational(-numerator(), denominator(), no_normalize{});
  75. }
  76. private:
  77. struct no_normalize{};
  78. rational(int_type num_, int_type den_, no_normalize)
  79. : m_numerator(num_), m_denominator(den_)
  80. {}
  81.  
  82. void normalize() {
  83. const int_type p = pgcd(std::abs(numerator()), denominator());
  84. m_numerator /= p;
  85. m_denominator /= p;
  86. }
  87. friend rational inverse(rational const&);
  88.  
  89. void check_invariants() const {
  90. assert(denominator() && "Denominator can't be null");
  91. assert(denominator()>0 && "Denominator can't be negative");
  92. assert(pgcd(std::abs(numerator()), denominator()) == 1 && "The rational shall be normalized");
  93. }
  94. friend class InvariantChecker<rational>;
  95.  
  96. int_type m_numerator;
  97. int_type m_denominator;
  98. };
  99.  
  100. bool operator==(rational const& rhs_, rational const& lhs_)
  101. { return rhs_.numerator() == lhs_.numerator() && rhs_.denominator() == lhs_.denominator(); }
  102. bool operator!=(rational const& rhs_, rational const& lhs_)
  103. { return ! (rhs_ == lhs_); }
  104.  
  105. /** Inverses a rational.
  106.  * @pre <tt>r != 0</tt>
  107.  */
  108. rational inverse(rational const& r) {
  109. assert(r != 0 && "Zero cannot be inversed");
  110. return rational(
  111. r.numerator() < 0 ? - r.denominator() : r.denominator(),
  112. std::abs(r.numerator()),
  113. rational::no_normalize{});
  114. }
  115.  
  116. rational& rational::operator/=(rational const& rhs_) {
  117. assert(rhs_ != rational{0} && "Cannot divide by zero");
  118. InvariantChecker<rational> check(*this);
  119. m_numerator *= rhs_.denominator();
  120. m_denominator *= rhs_.numerator();
  121. normalize();
  122. return *this;
  123. }
  124.  
  125.  
  126. std::ostream & operator<<(std::ostream & os, const rational & v)
  127. {
  128. return os << "\\frac{" << v.numerator() << "}{" << v.denominator() << "}";
  129. }
  130.  
  131. rational operator+(rational rhs_, rational const& lhs_)
  132. { return rhs_ += lhs_; }
  133. rational operator-(rational rhs_, rational const& lhs_)
  134. { return rhs_ -= lhs_; }
  135. rational operator*(rational rhs_, rational const& lhs_)
  136. { return rhs_ *= lhs_; }
  137. rational operator/(rational rhs_, rational const& lhs_)
  138. { return rhs_ /= lhs_; }
  139.  
  140.  
  141. #include <iostream>
  142. int main ()
  143. {
  144. assert(rational(0,1).numerator() == 0);
  145. assert(rational(0,1).denominator() == 1);
  146. assert(rational(10,5).numerator() == 2);
  147. assert(( rational{-10,5} == - rational{2}));
  148. assert(( inverse(rational{-11,5}) == rational{-5,11}));
  149.  
  150. assert((rational{1} + rational{3,2} == rational{5,2}));
  151. assert((rational{1,4} + rational{2,3} == rational{11,12}));
  152.  
  153. assert((rational{5} * rational{3,2} == rational{15,2}));
  154. assert((rational{10} * rational{3,2} == rational{15}));
  155.  
  156. assert((rational{5} / rational{3,2} == rational{10,3}));
  157. assert((rational{10} / rational{3,2} == rational{20,3}));
  158. assert((inverse(rational{1,3}) == rational{3}));
  159.  
  160. // precondition failures
  161. // auto f1 = rational{1,2} / rational{0};
  162. // auto f2 = inverse(rational{0});
  163.  
  164. std::cout << rational{4,8} + rational{2,3} << "\n";
  165. }
  166. // Vim: let $CXXFLAGS='-std=c++0x -g'
Success #stdin #stdout 0s 3352KB
stdin
Standard input is empty
stdout
\frac{7}{6}