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