1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "common/debug.h"
24 #include "common/rational.h"
25 #include "common/util.h"
26 #include "common/algorithm.h"
27 
28 namespace Common {
29 
Rational()30 Rational::Rational() {
31 	_num   = 1;
32 	_denom = 1;
33 }
34 
Rational(int num)35 Rational::Rational(int num) {
36 	_num   = num;
37 	_denom = 1;
38 }
39 
Rational(int num,int denom)40 Rational::Rational(int num, int denom) {
41 	assert(denom != 0);
42 
43 	if (denom > 0) {
44 		_num   = num;
45 		_denom = denom;
46 	} else {
47 		_num   = -num;
48 		_denom = -denom;
49 	}
50 
51 	cancel();
52 }
53 
cancel()54 void Rational::cancel() {
55 	// Cancel the fraction by dividing both the num and the denom
56 	// by their greatest common divisor.
57 
58 	const int gcd = Common::gcd(_num, _denom);
59 
60 	_num   /= gcd;
61 	_denom /= gcd;
62 }
63 
operator =(const Rational & right)64 Rational &Rational::operator=(const Rational &right) {
65 	_num   = right._num;
66 	_denom = right._denom;
67 
68 	return *this;
69 }
70 
operator =(int right)71 Rational &Rational::operator=(int right) {
72 	_num   = right;
73 	_denom = 1;
74 
75 	return *this;
76 }
77 
operator +=(const Rational & right)78 Rational &Rational::operator+=(const Rational &right) {
79 	// Cancel common factors to avoid unnecessary overflow.
80 	// Note that the result is *not* always normalized.
81 	const int gcd = Common::gcd(_denom, right._denom);
82 
83 	_num    = _num * (right._denom / gcd);
84 	_denom  = _denom / gcd;
85 	_num   += right._num * _denom;
86 	_denom *= right._denom;
87 
88 	cancel();
89 
90 	return *this;
91 }
92 
operator -=(const Rational & right)93 Rational &Rational::operator-=(const Rational &right) {
94 	// Cancel common factors to avoid unnecessary overflow.
95 	// Note that the result is *not* always normalized.
96 	const int gcd = Common::gcd(_denom, right._denom);
97 
98 	_num    = _num * (right._denom / gcd);
99 	_denom  = _denom / gcd;
100 	_num   -= right._num * _denom;
101 	_denom *= right._denom;
102 
103 	cancel();
104 
105 	return *this;
106 }
107 
operator *=(const Rational & right)108 Rational &Rational::operator*=(const Rational &right) {
109 	// Cross-cancel to avoid unnecessary overflow;
110 	// the result then is automatically normalized
111 	const int gcd1 = gcd(_num, right._denom);
112 	const int gcd2 = gcd(right._num, _denom);
113 
114 	_num   = (_num    / gcd1) * (right._num    / gcd2);
115 	_denom = (_denom  / gcd2) * (right._denom  / gcd1);
116 
117 	return *this;
118 }
119 
operator /=(const Rational & right)120 Rational &Rational::operator/=(const Rational &right) {
121 	return *this *= right.getInverse();
122 }
123 
operator +=(int right)124 Rational &Rational::operator+=(int right) {
125 	return *this += Rational(right);
126 }
127 
operator -=(int right)128 Rational &Rational::operator-=(int right) {
129 	return *this -= Rational(right);
130 }
131 
operator *=(int right)132 Rational &Rational::operator*=(int right) {
133 	return *this *= Rational(right);
134 }
135 
operator /=(int right)136 Rational &Rational::operator/=(int right) {
137 	return *this /= Rational(right);
138 }
139 
operator -() const140 const Rational Rational::operator-() const {
141 	return Rational(-_num, _denom);
142 }
143 
operator +(const Rational & right) const144 const Rational Rational::operator+(const Rational &right) const {
145 	Rational tmp = *this;
146 	tmp += right;
147 	return tmp;
148 }
149 
operator -(const Rational & right) const150 const Rational Rational::operator-(const Rational &right) const {
151 	Rational tmp = *this;
152 	tmp -= right;
153 	return tmp;
154 }
155 
operator *(const Rational & right) const156 const Rational Rational::operator*(const Rational &right) const {
157 	Rational tmp = *this;
158 	tmp *= right;
159 	return tmp;
160 }
161 
operator /(const Rational & right) const162 const Rational Rational::operator/(const Rational &right) const {
163 	Rational tmp = *this;
164 	tmp /= right;
165 	return tmp;
166 }
167 
operator +(int right) const168 const Rational Rational::operator+(int right) const {
169 	Rational tmp = *this;
170 	tmp += right;
171 	return tmp;
172 }
173 
operator -(int right) const174 const Rational Rational::operator-(int right) const {
175 	Rational tmp = *this;
176 	tmp -= right;
177 	return tmp;
178 }
179 
operator *(int right) const180 const Rational Rational::operator*(int right) const {
181 	Rational tmp = *this;
182 	tmp *= right;
183 	return tmp;
184 }
185 
operator /(int right) const186 const Rational Rational::operator/(int right) const {
187 	Rational tmp = *this;
188 	tmp /= right;
189 	return tmp;
190 }
191 
operator ==(const Rational & right) const192 bool Rational::operator==(const Rational &right) const {
193 	return (_num == right._num) && (_denom == right._denom);
194 }
195 
operator !=(const Rational & right) const196 bool Rational::operator!=(const Rational &right) const {
197 	return (_num != right._num) || (_denom != right._denom);
198 }
199 
operator >(const Rational & right) const200 bool Rational::operator>(const Rational &right) const {
201 	return (_num * right._denom) > (right._num * _denom);
202 }
203 
operator <(const Rational & right) const204 bool Rational::operator<(const Rational &right) const {
205 	return (_num * right._denom) < (right._num * _denom);
206 }
207 
operator >=(const Rational & right) const208 bool Rational::operator>=(const Rational &right) const {
209 	return (_num * right._denom) >= (right._num * _denom);
210 }
211 
operator <=(const Rational & right) const212 bool Rational::operator<=(const Rational &right) const {
213 	return (_num * right._denom) <= (right._num * _denom);
214 }
215 
operator ==(int right) const216 bool Rational::operator==(int right) const {
217 	return (_denom == 1) && (_num == right);
218 }
219 
operator !=(int right) const220 bool Rational::operator!=(int right) const {
221 	return (_denom != 1) || (_num != right);
222 }
223 
operator >(int right) const224 bool Rational::operator>(int right) const {
225 	return *this > Rational(right, 1);
226 }
227 
operator <(int right) const228 bool Rational::operator<(int right) const {
229 	return *this < Rational(right, 1);
230 }
231 
operator >=(int right) const232 bool Rational::operator>=(int right) const {
233 	return *this >= Rational(right, 1);
234 }
235 
operator <=(int right) const236 bool Rational::operator<=(int right) const {
237 	return *this <= Rational(right, 1);
238 }
239 
invert()240 void Rational::invert() {
241 	assert(_num != 0);
242 
243 	SWAP(_num, _denom);
244 
245 	if (_denom < 0) {
246 		_denom = -_denom;
247 		_num = -_num;
248 	}
249 }
250 
getInverse() const251 Rational Rational::getInverse() const {
252 	Rational inverse = *this;
253 
254 	inverse.invert();
255 
256 	return inverse;
257 }
258 
toInt() const259 int Rational::toInt() const {
260 	return _num / _denom;
261 }
262 
toDouble() const263 double Rational::toDouble() const {
264 	return ((double)_num) / ((double)_denom);
265 }
266 
toFrac() const267 frac_t Rational::toFrac() const {
268 	return (_num * FRAC_ONE) / _denom;
269 }
270 
operator +(int left,const Rational & right)271 const Rational operator+(int left, const Rational &right) {
272 	Rational tmp(left);
273 	tmp += right;
274 	return tmp;
275 }
276 
operator -(int left,const Rational & right)277 const Rational operator-(int left, const Rational &right) {
278 	Rational tmp(left);
279 	tmp -= right;
280 	return tmp;
281 }
282 
operator *(int left,const Rational & right)283 const Rational operator*(int left, const Rational &right) {
284 	Rational tmp(left);
285 	tmp *= right;
286 	return tmp;
287 }
288 
operator /(int left,const Rational & right)289 const Rational operator/(int left, const Rational &right) {
290 	Rational tmp(left);
291 	tmp /= right;
292 	return tmp;
293 }
294 
debugPrint(int debuglevel,const char * caption) const295 void Rational::debugPrint(int debuglevel, const char *caption) const {
296 	debug(debuglevel, "%s %d/%d", caption, _num, _denom);
297 }
298 
operator ==(int left,const Rational & right)299 bool operator==(int left, const Rational &right) {
300 	return right == left;
301 }
302 
operator !=(int left,const Rational & right)303 bool operator!=(int left, const Rational &right) {
304 	return right != left;
305 }
306 
operator >(int left,const Rational & right)307 bool operator>(int left, const Rational &right) {
308 	return right < left;
309 }
310 
operator <(int left,const Rational & right)311 bool operator<(int left, const Rational &right) {
312 	return right > left;
313 }
314 
operator >=(int left,const Rational & right)315 bool operator>=(int left, const Rational &right) {
316 	return right <= left;
317 }
318 
operator <=(int left,const Rational & right)319 bool operator<=(int left, const Rational &right) {
320 	return right >= left;
321 }
322 
323 } // End of namespace Common
324