moved kdeaccessibility kdeaddons kdeadmin kdeartwork kdebindings kdeedu kdegames...
[kdeedu.git] / kbruch / src / ratio.cpp
blob289e79f92d627d331bc8fcd681c3516eb2842b0f
1 /***************************************************************************
2 ratio.cpp - source code of class ratio
3 -------------------
4 begin : Tue Nov 27 16:40:42 CET 2001
5 copyright : (C) 2001-2004 by Sebastian Stein
6 email : seb.kde@hpfsc.de
7 ***************************************************************************/
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
18 #include <kdebug.h>
20 #include "ratio.h"
21 #include "primenumber.h"
23 /* ----- public member functions ----- */
25 /* constructor */
26 ratio::ratio(int pnumerator, int pdenominator):m_numerator(pnumerator), m_denominator(pdenominator)
28 #ifdef DEBUG
29 kdDebug() << "constructor ratio" << endl;
30 #endif
32 // denominator is never allowed to be 0
33 if (!m_denominator)
34 m_denominator = 1;
36 // reduce the new ratio
37 reduce();
40 /* copy constructor */
41 ratio::ratio(const ratio & copy_ratio)
43 #ifdef DEBUG
44 kdDebug() << "copy constructor ratio" << endl;
45 #endif
47 setNumerator(copy_ratio.numerator(), false);
48 setDenominator(copy_ratio.denominator(), false);
51 /* destructor */
52 ratio::~ratio()
54 #ifdef DEBUG
55 kdDebug() << "destructor ratio" << endl;
56 #endif
59 /* displays the ratio on stdout; just for debugging */
60 QTextStream & ratio::display(QTextStream & str) const
62 int tmp_width = str.width();
63 str << qSetW(5) << " ";
64 str << qSetW(5) << m_numerator << endl;
65 str << qSetW(tmp_width) << " ";
66 str << " ----- " << endl;
67 str << qSetW(tmp_width) << " ";
68 return str << qSetW(5) << m_denominator;
71 /* return the numerator */
72 int ratio::numerator() const
74 return m_numerator;
77 /* return the denominator */
78 int ratio::denominator() const
80 return m_denominator;
83 /* set the numerator */
84 void ratio::setNumerator(int pnumerator, bool reduce_it)
86 m_numerator = pnumerator;
88 // check, if we have to reduce the ratio
89 if (reduce_it == true)
90 reduce();
92 return;
95 /* set the denominator */
96 void ratio::setDenominator(int pdenominator, bool reduce_it)
98 /* denominator is not allowed to be 0 */
99 if (!pdenominator)
100 pdenominator = 1;
102 m_denominator = pdenominator;
104 // check, if we have to reduce the ratio
105 if (reduce_it == true)
106 reduce();
108 return;
111 /* add a ratio to a ratio like c = a + b */
112 ratio ratio::operator+(ratio addend)
114 // this object will be returned as the sum
115 ratio sum(0, 1);
117 // calculate and set the numerator without reducing
118 sum.setNumerator(m_numerator * addend.denominator()
119 + addend.numerator() * m_denominator, false);
121 // calculate and set the denominator without reducing
122 sum.setDenominator(m_denominator * addend.denominator(), false);
124 // reduce the sum
125 sum.reduce();
127 return sum;
130 /* sub a ratio from a ratio like c = a - b */
131 ratio ratio::operator-(ratio subtrahend)
133 /* this object will be returned as the difference */
134 ratio diff(0, 1);
136 /* change the sign of the subtrahend, so we can handle it as an addition */
137 subtrahend.change_sign();
138 diff = operator+(subtrahend);
140 /* we have to change the sign back, so everything will be as before */
141 subtrahend.change_sign();
143 /* return the difference */
144 return diff;
147 /* mul a ratio with a ratio like c = a * b */
148 ratio ratio::operator*(ratio factor)
150 // this object will be returned as the product
151 ratio product(0, 1);
153 // calculate and set numerator and denominator without reducing
154 product.setNumerator(m_numerator * factor.numerator(), false);
155 product.setDenominator(m_denominator * factor.denominator(), false);
157 // reduce the product
158 product.reduce();
160 return product;
163 /* div a ratio with a ratio like c = a / b */
164 ratio ratio::operator/(ratio divisor)
166 /* this object will be returned as the quotient */
167 ratio quotient(0, 1);
169 /* exchange numerator and denominator so we can handle as multiplication */
170 divisor.reziproc();
171 quotient = operator*(divisor);
173 /* go back to the original state */
174 divisor.reziproc();
176 return quotient;
179 /* we need this for initialization during a function prototyp;
180 * ratio fraction = 0 */
181 ratio ratio::operator=(int dummy)
183 m_numerator = dummy;
184 m_denominator = 1;
186 return *this;
189 /* check, if the ratios are equivalent; -1/2 == 1/-2 -> TRUE */
190 bool ratio::operator==(ratio right)
192 signed short orig_sign = 1, right_sign = 1;
194 /* we do not check the presign at this point */
195 if (QABS(m_numerator) != QABS(right.numerator()))
196 return false;
197 if (QABS(m_denominator) != QABS(right.denominator()))
198 return false;
200 /* check if the signs of the ratios are equivalent */
201 if (m_numerator < 0)
202 orig_sign = -1;
203 if (m_denominator < 0)
204 orig_sign *= -1;
205 if (right.numerator() < 0)
206 right_sign = -1;
207 if (right.denominator() < 0)
208 right_sign *= -1;
210 if (orig_sign != right_sign)
211 return false;
213 return true;
216 bool ratio::operator<(ratio right)
218 signed short sign = 1;
219 ratio tmp_ratio = ratio(m_numerator, m_denominator) - right;
221 // check for this == right
222 if (tmp_ratio == ratio(0, 1))
223 return false;
225 // get the presign of the diff
226 if (tmp_ratio.numerator() < 0)
227 sign = -1;
228 if (tmp_ratio.denominator() < 0)
229 sign *= -1;
231 // if the diff is negative, this is smaller then right
232 if (sign > 0)
234 return false;
235 } else {
236 return true;
240 bool ratio::operator>(ratio right)
242 signed short sign = 1;
243 ratio tmp_ratio = ratio(m_numerator, m_denominator) - right;
245 // check for this == right
246 if (tmp_ratio == ratio(0, 1))
247 return false;
249 // get the presign of the diff
250 if (tmp_ratio.numerator() < 0)
251 sign = -1;
252 if (tmp_ratio.denominator() < 0)
253 sign *= -1;
255 // if the diff is positive, this is smaller then right
256 if (sign < 0)
258 return false;
259 } else {
260 return true;
264 /* ----- private member functions ----- */
266 /* reduce the ratio */
267 void ratio::reduce()
269 /* we try prime numbers as divisors; I think it is the fastet way to do */
270 primenumber number;
271 short sign_numerator = 0, sign_denominator = 0;
273 /* make the whole ratio positive; save the signs; it is easier to reduce
274 * the ratio, if it is positive */
275 if (m_numerator < 0) // save numerator sign
277 sign_numerator = 1;
278 m_numerator *= -1;
280 if (m_denominator < 0) // save denominator sign
282 sign_denominator = 1;
283 m_denominator *= -1;
286 for (int divisor = number.get_first();
287 divisor <= m_numerator && divisor <= m_denominator; divisor = number.get_next())
289 if (divisor == 0)
291 #ifdef DEBUG
292 kdDebug() << "ratio::reduce() -> divisor == 0 !!!" << endl;
293 kdDebug() << "m_numerator: " << m_numerator << endl;
294 kdDebug() << "m_denominator: " << m_denominator << endl;
295 // cin.get();
296 #endif
297 /* so that the application does not crash with a floating
298 * point exception; the error should not appear, but in some
299 * cases it does and I do not know why */
300 continue;
303 /* is the prime number a divisor of numerator and denominator? */
304 if ((m_numerator % divisor == 0) && (m_denominator % divisor == 0))
306 /* reduce the ratio by the divisor */
307 m_numerator /= divisor;
308 m_denominator /= divisor;
310 /* we have to go recursive, if the 2 is a divisor, because there
311 * is no way to step one number before 2 -> there is no prime
312 * number smaller than 2 */
313 if (divisor == 2)
314 reduce();
315 else
316 number.move_back(); // the prime number could be a divisor again
317 } // if ((zaehler % divisor == 0) && (nenner % divisor == 0))
318 } // for (unsigned int divisor = number.get_first(); ...
320 /* restore the correct signs */
321 if (sign_numerator)
322 m_numerator *= -1;
323 if (sign_denominator)
324 m_denominator *= -1;
325 if (m_numerator == 0)
326 m_denominator = 1;
328 return;
331 /* exchange numerator and denominator */
332 void ratio::reziproc()
334 int temp = m_numerator;
335 m_numerator = m_denominator;
336 m_denominator = temp;
338 return;
342 /* ------ private member functions ------ */
344 /* change the sign of the ratio; ratio = ratio * -1 */
345 void ratio::change_sign()
347 /* this would be enough to change the sign of the ratio */
348 m_numerator *= -1;
350 /* if numerator and denominator both are negative, make them positive;
351 * if denominator is negative and numerator positive, exchange the sign */
352 if ((m_numerator < 0 && m_denominator < 0) || (m_numerator > 0 && m_denominator < 0))
354 m_numerator *= -1;
355 m_denominator *= -1;
358 return;
362 /* ------ some prototyps of non class functions ------ */
364 // it is possible to stram ratio_object
365 QTextStream & operator<<(QTextStream & str, const ratio & pratio)
367 return pratio.display(str);