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