1 /*
2 Ratio.cpp - source code of class Ratio
3 SPDX-FileCopyrightText: 2001-2004 Sebastian Stein <seb.kde@hpfsc.de>
4 SPDX-FileCopyrightText: 2008 Tadeu Araujo <tadeu.araujo@ltia.fc.unesp.br>
5 SPDX-FileCopyrightText: 2008 Danilo Balzaque <danilo.balzaque@ltia.fc.unesp.br>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "Ratio.h"
11
12 #ifdef DEBUG
13 #include <QDebug>
14 #endif
15
16 #include "PrimeNumber.h"
17
18
19 /* ----- public member functions ----- */
20
21 /* constructor */
Ratio(int pnumerator,int pdenominator)22 Ratio::Ratio(int pnumerator, int pdenominator) : m_numerator(pnumerator), m_denominator(pdenominator)
23 {
24 #ifdef DEBUG
25 qDebug() << "constructor ratio";
26 #endif
27
28 // denominator is never allowed to be 0
29 if (!m_denominator)
30 m_denominator = 1;
31
32 // reduce the new ratio
33 reduce();
34 }
35
Ratio(int pnumerator,int pdenominator,bool reduce_fraction)36 Ratio::Ratio(int pnumerator, int pdenominator, bool reduce_fraction) : m_numerator(pnumerator), m_denominator(pdenominator)
37 {
38 #ifdef DEBUG
39 qDebug() << "constructor ratio";
40 #endif
41
42 // denominator is never allowed to be 0
43 if (!m_denominator)
44 m_denominator = 1;
45
46 // reduce the new ratio
47 if (reduce_fraction)
48 reduce();
49 }
50
51 /* copy constructor */
Ratio(const Ratio & copy_ratio)52 Ratio::Ratio(const Ratio & copy_ratio)
53 {
54 #ifdef DEBUG
55 qDebug() << "copy constructor ratio";
56 #endif
57 setNumerator(copy_ratio.numerator(), false);
58 setDenominator(copy_ratio.denominator(), false);
59 }
60
61 /* destructor */
~Ratio()62 Ratio::~Ratio()
63 {
64 #ifdef DEBUG
65 qDebug() << "destructor ratio";
66 #endif
67 }
68
69 /* displays the ratio on stdout; just for debugging */
display(QTextStream & str) const70 QTextStream & Ratio::display(QTextStream & str) const
71 {
72 int tmp_width = str.fieldWidth();
73 str << qSetFieldWidth(5) << " ";
74 str << qSetFieldWidth(5) << m_numerator << QLatin1Char('\n');
75 str << qSetFieldWidth(tmp_width) << " ";
76 str << " ----- " << QLatin1Char('\n');
77 str << qSetFieldWidth(tmp_width) << " ";
78 str << qSetFieldWidth(5) << m_denominator;
79 str.flush();
80 return str;
81 }
82
83 /* return the numerator */
numerator() const84 int Ratio::numerator() const
85 {
86 return m_numerator;
87 }
88
89 /* return the denominator */
denominator() const90 int Ratio::denominator() const
91 {
92 return m_denominator;
93 }
94
95 /* set the numerator */
setNumerator(int pnumerator,bool reduce_it)96 void Ratio::setNumerator(int pnumerator, bool reduce_it)
97 {
98 m_numerator = pnumerator;
99
100 // check, if we have to reduce the ratio
101 if (reduce_it == true)
102 reduce();
103
104 return;
105 }
106
107 /* set the denominator */
setDenominator(int pdenominator,bool reduce_it)108 void Ratio::setDenominator(int pdenominator, bool reduce_it)
109 {
110 /* denominator is not allowed to be 0 */
111 if (!pdenominator)
112 pdenominator = 1;
113
114 m_denominator = pdenominator;
115
116 // check, if we have to reduce the ratio
117 if (reduce_it == true)
118 reduce();
119
120 return;
121 }
122
123 /* set completely new ratio */
setRatio(int pnumerator,int pdenominator,bool reduce_it)124 void Ratio::setRatio(int pnumerator, int pdenominator, bool reduce_it)
125 {
126 setNumerator(pnumerator, false);
127 setDenominator(pdenominator, false);
128
129 // check, if we have to reduce the ratio
130 if (reduce_it == true) {
131 reduce();
132 }
133
134 return;
135 }
136
137 /* set completely new ratio using mixed numbers */
setRatio(int pinteger,int pnumerator,int pdenominator,bool reduce_it)138 void Ratio::setRatio(int pinteger, int pnumerator, int pdenominator, bool reduce_it)
139 {
140 // calculate new Numerator, but ignore negative values
141 int newNumerator = qAbs(pinteger * pdenominator) + qAbs(pnumerator);
142
143 // restore negative values
144 if ((pinteger < 0 || pnumerator < 0) && !(pinteger < 0 && pnumerator < 0))
145 newNumerator *= -1;
146
147 setRatio(newNumerator, pdenominator, reduce_it);
148
149 return;
150 }
151
152
153 /* add a ratio to a ratio like c = a + b */
operator +(const Ratio & addend)154 Ratio Ratio::operator+ (const Ratio &addend)
155 {
156 // this object will be returned as the sum
157 Ratio sum(0, 1);
158
159 // calculate and set the numerator without reducing
160 sum.setNumerator(m_numerator * addend.denominator()
161 + addend.numerator() * m_denominator, false);
162
163 // calculate and set the denominator without reducing
164 sum.setDenominator(m_denominator * addend.denominator(), false);
165
166 // reduce the sum
167 sum.reduce();
168
169 return sum;
170 }
171
172 /* sub a ratio from a ratio like c = a - b */
operator -(Ratio subtrahend)173 Ratio Ratio::operator- (Ratio subtrahend)
174 {
175 /* this object will be returned as the difference */
176 Ratio diff(0, 1);
177
178 /* change the sign of the subtrahend, so we can handle it as an addition */
179 subtrahend.change_sign();
180 diff = operator+ (subtrahend);
181
182 /* we have to change the sign back, so everything will be as before */
183 subtrahend.change_sign();
184
185 /* return the difference */
186 return diff;
187 }
188
189 /* mul a ratio with a ratio like c = a * b */
operator *(const Ratio & factor)190 Ratio Ratio::operator*(const Ratio &factor)
191 {
192 // this object will be returned as the product
193 Ratio product(0, 1);
194
195 // calculate and set numerator and denominator without reducing
196 product.setNumerator(m_numerator * factor.numerator(), false);
197 product.setDenominator(m_denominator * factor.denominator(), false);
198
199 // reduce the product
200 product.reduce();
201
202 return product;
203 }
204
205 /* div a ratio with a ratio like c = a / b */
operator /(Ratio divisor)206 Ratio Ratio::operator/ (Ratio divisor)
207 {
208 /* this object will be returned as the quotient */
209 Ratio quotient(0, 1);
210
211 /* exchange numerator and denominator so we can handle as multiplication */
212 divisor.reziproc();
213 quotient = operator* (divisor);
214
215 /* go back to the original state */
216 divisor.reziproc();
217
218 return quotient;
219 }
220
221 /* we need this for initialization during a function prototyp;
222 * ratio fraction = 0 */
operator =(int dummy)223 Ratio Ratio::operator= (int dummy)
224 {
225 m_numerator = dummy;
226 m_denominator = 1;
227
228 return *this;
229 }
230
231 /* check, if the ratios are equivalent; -1/2 == 1/-2 -> true */
operator ==(const Ratio & right)232 bool Ratio::operator== (const Ratio &right)
233 {
234 signed short orig_sign = 1, right_sign = 1;
235
236 /* we do not check the presign at this point */
237 if (qAbs(m_numerator) != qAbs(right.numerator()))
238 return false;
239 if (qAbs(m_denominator) != qAbs(right.denominator()))
240 return false;
241
242 /* check if the signs of the ratios are equivalent */
243 if (m_numerator < 0)
244 orig_sign = -1;
245 if (m_denominator < 0)
246 orig_sign *= -1;
247 if (right.numerator() < 0)
248 right_sign = -1;
249 if (right.denominator() < 0)
250 right_sign *= -1;
251
252 if (orig_sign != right_sign)
253 return false;
254
255 return true;
256 }
257
operator <(const Ratio & right)258 bool Ratio::operator< (const Ratio &right)
259 {
260 signed short sign = 1;
261 Ratio tmp_ratio = Ratio(m_numerator, m_denominator) - right;
262
263 // check for this == right
264 if (tmp_ratio == Ratio(0, 1))
265 return false;
266
267 // get the presign of the diff
268 if (tmp_ratio.numerator() < 0)
269 sign = -1;
270 if (tmp_ratio.denominator() < 0)
271 sign *= -1;
272
273 // if the diff is negative, this is smaller than right
274 if (sign > 0) {
275 return false;
276 } else {
277 return true;
278 }
279 }
280
operator >(const Ratio & right)281 bool Ratio::operator> (const Ratio &right)
282 {
283 signed short sign = 1;
284 Ratio tmp_ratio = Ratio(m_numerator, m_denominator) - right;
285
286 // check for this == right
287 if (tmp_ratio == Ratio(0, 1))
288 return false;
289
290 // get the presign of the diff
291 if (tmp_ratio.numerator() < 0)
292 sign = -1;
293 if (tmp_ratio.denominator() < 0)
294 sign *= -1;
295
296 // if the diff is positive, this is smaller than right
297 if (sign < 0) {
298 return false;
299 } else {
300 return true;
301 }
302 }
303
304 /* ----- private member functions ----- */
305
306 /* reduce the ratio */
reduce()307 void Ratio::reduce()
308 {
309 /* we try prime numbers as divisors; I think it is the fastest way to do */
310 PrimeNumber number;
311 short sign_numerator = 0, sign_denominator = 0;
312
313 /* make the whole ratio positive; save the signs; it is easier to reduce
314 * the ratio, if it is positive */
315 if (m_numerator < 0) { // save numerator sign
316 sign_numerator = 1;
317 m_numerator *= -1;
318 }
319 if (m_denominator < 0) { // save denominator sign
320 sign_denominator = 1;
321 m_denominator *= -1;
322 }
323
324 for (int divisor = number.get_first();
325 divisor <= m_numerator && divisor <= m_denominator; divisor = number.get_next()) {
326 if (divisor == 0) {
327 #ifdef DEBUG
328 qDebug() << "ratio::reduce() -> divisor == 0 !!!";
329 qDebug() << "m_numerator: " << m_numerator;
330 qDebug() << "m_denominator: " << m_denominator;
331 // cin.get();
332 #endif
333 /* so that the application does not crash with a floating
334 * point exception; the error should not appear, but in some
335 * cases it does and I do not know why */
336 continue;
337 }
338
339 /* is the prime number a divisor of numerator and denominator? */
340 if ((m_numerator % divisor == 0) && (m_denominator % divisor == 0)) {
341 /* reduce the ratio by the divisor */
342 m_numerator /= divisor;
343 m_denominator /= divisor;
344
345 /* we have to go recursive, if the 2 is a divisor, because there
346 * is no way to step one number before 2 -> there is no prime
347 * number smaller than 2 */
348 if (divisor == 2)
349 reduce();
350 else
351 number.move_back(); // the prime number could be a divisor again
352 } // if ((zaehler % divisor == 0) && (nenner % divisor == 0))
353 } // for (unsigned int divisor = number.get_first(); ...
354
355 /* restore the correct signs */
356 if (sign_numerator)
357 m_numerator *= -1;
358 if (sign_denominator)
359 m_denominator *= -1;
360 if (m_numerator == 0)
361 m_denominator = 1;
362
363 return;
364 }
365
366 /* exchange numerator and denominator */
reziproc()367 void Ratio::reziproc()
368 {
369 int temp = m_numerator;
370 m_numerator = m_denominator;
371 m_denominator = temp;
372
373 return;
374 }
375
376 /* ------ private member functions ------ */
377
378 /* change the sign of the ratio; ratio = ratio * -1 */
change_sign()379 void Ratio::change_sign()
380 {
381 /* this would be enough to change the sign of the ratio */
382 m_numerator *= -1;
383
384 /* if numerator and denominator both are negative, make them positive;
385 * if denominator is negative and numerator positive, exchange the sign */
386 if ((m_numerator < 0 && m_denominator < 0) || (m_numerator > 0 && m_denominator < 0)) {
387 m_numerator *= -1;
388 m_denominator *= -1;
389 }
390
391 return;
392 }
393
394
395 /* ------ some prototyps of non class functions ------ */
396
397 // it is possible to stram ratio_object
operator <<(QTextStream & str,const Ratio & pratio)398 QTextStream & operator<< (QTextStream & str, const Ratio & pratio)
399 {
400 return pratio.display(str);
401 }
402