fraction
Below is the complete fraction class (written in most idiomatic way), with everything that was used in any lesson (with all possible improvements).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
#include <iostream> #include <cassert> // (greatest common divisor) // if you have C++17, you can remove this function and use std::gcd from <numeric> int gcd(int a, int b) { if (b == 0) return a; else return gcd(b, a % b); } class fraction { public: fraction(int numerator = 0, int denominator = 1) : m_numerator(numerator) , m_denominator(make_valid_denominator(denominator)) {} void simplify() { const int n = gcd(m_numerator, m_denominator); m_numerator /= n; m_denominator /= n; } int numerator() const { return m_numerator; } void numerator(int value) { m_numerator = value; } int denominator() const { return m_denominator; } void denominator(int value) { m_denominator = make_valid_denominator(value); } void print(std::ostream& os = std::cout) const { os << m_numerator << "/" << m_denominator; } double approx() const { return static_cast<double>(m_numerator) / m_denominator; } operator double() const { return approx(); } fraction& operator+=(fraction rhs) { m_numerator = numerator() * rhs.denominator() + rhs.numerator() * denominator(); m_denominator = denominator() * rhs.denominator(); simplify(); return *this; } fraction& operator-=(fraction rhs) { m_numerator = numerator() * rhs.denominator() - rhs.numerator() * denominator(); m_denominator = denominator() * rhs.denominator(); simplify(); return *this; } fraction& operator*=(fraction rhs) { m_numerator *= rhs.numerator(); m_denominator *= rhs.denominator(); simplify(); return *this; } fraction& operator/=(fraction rhs) { assert(rhs.numerator() != 0); m_numerator *= rhs.denominator(); m_denominator *= rhs.numerator(); simplify(); return *this; } fraction& operator%=(fraction rhs) { assert(rhs.numerator() != 0); m_numerator = (numerator() * rhs.denominator()) % (rhs.numerator() * denominator()); m_denominator *= rhs.denominator(); simplify(); return *this; } fraction& operator++() // (prefix) { m_numerator += m_denominator; return *this; } fraction& operator--() // (prefix) { m_numerator -= m_denominator; return *this; } fraction operator++(int) // (postfix) { fraction old = *this; operator++(); return old; } fraction operator--(int) // (postfix) { fraction old = *this; operator--(); return old; } private: static int make_valid_denominator(int value) { if (value == 0) return 1; else return value; } int m_numerator; int m_denominator; }; bool operator==(fraction lhs, fraction rhs) { if (lhs.denominator() == rhs.denominator()) return lhs.numerator() == rhs.numerator(); return lhs.numerator() * rhs.denominator() == rhs.numerator() * lhs.denominator(); } bool operator!=(fraction lhs, fraction rhs) { return !(lhs == rhs); } bool operator<(fraction lhs, fraction rhs) { if (lhs.denominator() == rhs.denominator()) return lhs.numerator() < rhs.numerator(); return lhs.numerator() * rhs.denominator() < rhs.numerator() * lhs.denominator(); } bool operator> (fraction lhs, fraction rhs) { return rhs < lhs; } bool operator<=(fraction lhs, fraction rhs) { return !(lhs > rhs); } bool operator>=(fraction lhs, fraction rhs) { return !(lhs < rhs); } fraction operator+(fraction lhs, fraction rhs) { return lhs += rhs; } fraction operator-(fraction lhs, fraction rhs) { return lhs -= rhs; } fraction operator*(fraction lhs, fraction rhs) { return lhs *= rhs; } fraction operator/(fraction lhs, fraction rhs) { return lhs /= rhs; } fraction operator%(fraction lhs, fraction rhs) { return lhs %= rhs; } std::ostream& operator<<(std::ostream& os, fraction fr) { fr.print(os); return os; } |
Couldn't the
gcd
function beconstexpr
?
Actually, everything except print
function can be constexpr
. Adding it is very trivial so I choose not to - it would only increase verbosity.