1 #ifndef _STEM4U_Rational_h_ 2 #define _STEM4U_Rational_h_ 3 4 namespace Upp { 5 6 class Rational : public Moveable<Rational> { 7 public: Rational()8 Rational() : num(0), den(1) {} Rational(const Rational & v)9 Rational(const Rational& v) { 10 num = v.num; 11 den = v.den; 12 } 13 template <typename T> Rational(T v)14 Rational(T v) { 15 *this = v; 16 } 17 template <typename T> Rational(T n,T d)18 Rational(T n, T d) { 19 if (d < 0) { 20 num = -n; 21 den = -d; 22 } else { 23 num = n; 24 den = d; 25 } 26 } Rational(double n,double d)27 Rational(double n, double d) { 28 *this = Rational(n)/Rational(d); 29 } 30 Rational operator-() const { 31 Rational ret = *this; 32 ret.num = -ret.num; 33 return ret; 34 } 35 bool operator<(const Rational& right) const { 36 intInf nd, right_nd; 37 nd = num/den; 38 right_nd = right.num/right.den; 39 if (nd < right_nd) 40 return true; 41 if (nd == right_nd) 42 return num%den < right.num%right.den; 43 return false; 44 } 45 template <typename T> 46 bool operator<(const T& right) const { 47 return num < den*intInf(right); 48 } 49 bool operator>(const Rational& right) const { 50 intInf nd, right_nd; 51 nd = num/den; 52 right_nd = right.num/right.den; 53 if (nd > right_nd) 54 return true; 55 if (nd == right_nd) 56 return num%den > right.num%right.den; 57 return false; 58 } 59 template <typename T> 60 bool operator>(const T& right) const { 61 return num > den*intInf(right); 62 } 63 template <typename T> 64 const Rational& operator=(T v) { 65 num = v; 66 den = 1; 67 return *this; 68 } 69 const Rational& operator=(double d) { 70 int exp; 71 double man = normalize(d, exp); 72 long long lman = static_cast<long long>(man*1E17); 73 num = lman; 74 den = 1; 75 if (exp > 0) 76 num *= intInf(("1" + String('0', exp)).Begin()); 77 else 78 den *= intInf(("1" + String('0', -exp)).Begin()); 79 den *= intInf(("1" + String('0', 17)).Begin()); 80 return *this; 81 } 82 void operator++() { 83 num++; 84 } 85 void operator--() { 86 num--; 87 } 88 void operator+=(const Rational& right) { 89 if (den == right.den) 90 num += right.num; 91 else { 92 num = num*right.den + den*right.num; 93 den *= right.den; 94 } 95 } 96 void operator-=(const Rational& right) { 97 if (den == right.den) 98 num -= right.num; 99 else { 100 num = num*right.den - den*right.num; 101 den *= right.den; 102 } 103 } 104 void operator*=(const Rational& right) { 105 num *= right.num; 106 den *= right.den; 107 } 108 void operator/=(const Rational& right) { 109 if (&right == this) 110 num = den = 1; 111 else { 112 if (right.num < 0) { 113 den *= -right.num; 114 num *= -right.den; 115 } else { 116 den *= right.num; 117 num *= right.den; 118 } 119 } 120 } 121 bool operator==(Rational& right) { 122 Simplify(); 123 right.Simplify(); 124 return num == right.num && den == right.den; 125 } 126 template <typename T> 127 bool operator==(T right) { 128 Simplify(); 129 if (den == 1) 130 return num == intInf(right); 131 else 132 return T(num/den) == right; 133 } 134 bool operator!=(Rational& right) {return !operator==(right);} 135 template <typename T> 136 bool operator!=(T right) {return !operator==(right);} 137 138 template <typename T> T()139 operator T() { 140 if (den == 0) 141 throw std::domain_error("Division by zero"); 142 if (den == 1) 143 return T(num); 144 Rational ret = T(num)/T(den); 145 return ret; 146 } 147 operator double() { 148 if (den == 0) 149 throw std::domain_error("Division by zero"); 150 if (den == 1) 151 return double(num.toLongLong()); 152 Rational ret = double(num.toLongLong())/double(num.toLongLong()); 153 return ret; 154 } 155 Rational Simplify(bool full = false); ToString()156 String ToString() const {return FormatRational(*this, Null);} 157 158 private: 159 intInf num, den; 160 SimplifyVal(const intInf & val)161 void SimplifyVal(const intInf &val) { 162 while (num%val == 0 && den%val == 0) { 163 num /= val; 164 den /= val; 165 } 166 } 167 168 friend Rational abs(const Rational &rat); 169 friend Rational pow(const Rational &l, int e); 170 friend Rational sqrt(const Rational &l); 171 friend String FormatRational(const Rational &d, int numDec); 172 173 template <typename T> 174 friend Rational operator+(T left, const Rational &right); 175 template <typename T> 176 friend Rational operator+(const Rational& left, T right); 177 friend Rational operator+(const Rational& left, const Rational& right); 178 template <typename T> 179 friend Rational operator-(T left, const Rational &right); 180 template <typename T> 181 friend Rational operator-(const Rational& left, T right); 182 friend Rational operator-(const Rational& left, const Rational& right); 183 template <typename T> 184 friend Rational operator*(T left, const Rational &right); 185 template <typename T> 186 friend Rational operator*(const Rational& left, T right); 187 friend Rational operator*(const Rational& left, const Rational& right); 188 template <typename T> 189 friend Rational operator/(T left, const Rational &right); 190 template <typename T> 191 friend Rational operator/(const Rational& left, T right); 192 friend Rational operator/(const Rational& left, const Rational& right); 193 }; 194 195 Rational abs(const Rational &l); 196 Rational pow(const Rational &l, int e); 197 Rational sqrt(const Rational &l); 198 String FormatRational(const Rational &d, int numDec); 199 200 template <typename T> 201 Rational operator+(T left, const Rational &right) { 202 Rational ret; 203 ret.num = right.den*left + right.num; 204 ret.den = right.den; 205 return ret; 206 } 207 208 template <typename T> 209 Rational operator+(const Rational& left, T right) { 210 Rational ret; 211 ret.num = left.num + right; 212 ret.den = left.den; 213 return ret; 214 } 215 216 template <typename T> 217 Rational operator-(T left, const Rational &right) { 218 Rational ret; 219 ret.num = right.den*left - right.num; 220 ret.den = right.den; 221 return ret; 222 } 223 224 template <typename T> 225 Rational operator-(const Rational& left, T right) { 226 Rational ret; 227 ret.num = left.num - left.den*right; 228 ret.den = left.den; 229 return ret; 230 } 231 232 template <typename T> 233 Rational operator*(T left, const Rational& right) { 234 Rational ret; 235 ret.num = right.num*intInf(left); 236 ret.den = right.den; 237 return ret; 238 } 239 240 template <typename T> 241 Rational operator*(const Rational& left, T right) { 242 Rational ret; 243 ret.num = left.num*intInf(right); 244 ret.den = left.den; 245 return ret; 246 } 247 248 template <typename T> 249 Rational operator/(T left, const Rational& right) { 250 Rational ret; 251 ret.num = right.den*left; 252 ret.den = right.num; 253 if (ret.den < 0) { 254 ret.num = -ret.num; 255 ret.den = -ret.den; 256 } 257 return ret; 258 } 259 260 template <typename T> 261 Rational operator/(const Rational& left, T right) { 262 Rational ret; 263 ret.num = left.num; 264 ret.den = left.den*right; 265 if (ret.den < 0) { 266 ret.num = -ret.num; 267 ret.den = -ret.den; 268 } 269 return ret; 270 } 271 272 } 273 274 #endif 275