File indexing completed on 2024-04-21 03:41:49
0001 /* 0002 Ratio.cpp - source code of class Ratio 0003 SPDX-FileCopyrightText: 2001-2004 Sebastian Stein <seb.kde@hpfsc.de> 0004 SPDX-FileCopyrightText: 2008 Tadeu Araujo <tadeu.araujo@ltia.fc.unesp.br> 0005 SPDX-FileCopyrightText: 2008 Danilo Balzaque <danilo.balzaque@ltia.fc.unesp.br> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "Ratio.h" 0011 0012 #ifdef DEBUG 0013 #include <QDebug> 0014 #endif 0015 0016 #include "PrimeNumber.h" 0017 0018 0019 /* ----- public member functions ----- */ 0020 0021 /* constructor */ 0022 Ratio::Ratio(int pnumerator, int pdenominator) : m_numerator(pnumerator), m_denominator(pdenominator) 0023 { 0024 #ifdef DEBUG 0025 qDebug() << "constructor ratio"; 0026 #endif 0027 0028 // denominator is never allowed to be 0 0029 if (!m_denominator) 0030 m_denominator = 1; 0031 0032 // reduce the new ratio 0033 reduce(); 0034 } 0035 0036 Ratio::Ratio(int pnumerator, int pdenominator, bool reduce_fraction) : m_numerator(pnumerator), m_denominator(pdenominator) 0037 { 0038 #ifdef DEBUG 0039 qDebug() << "constructor ratio"; 0040 #endif 0041 0042 // denominator is never allowed to be 0 0043 if (!m_denominator) 0044 m_denominator = 1; 0045 0046 // reduce the new ratio 0047 if (reduce_fraction) 0048 reduce(); 0049 } 0050 0051 /* destructor */ 0052 Ratio::~Ratio() 0053 { 0054 #ifdef DEBUG 0055 qDebug() << "destructor ratio"; 0056 #endif 0057 } 0058 0059 /* displays the ratio on stdout; just for debugging */ 0060 QTextStream & Ratio::display(QTextStream & str) const 0061 { 0062 int tmp_width = str.fieldWidth(); 0063 str << qSetFieldWidth(5) << " "; 0064 str << qSetFieldWidth(5) << m_numerator << QLatin1Char('\n'); 0065 str << qSetFieldWidth(tmp_width) << " "; 0066 str << " ----- " << QLatin1Char('\n'); 0067 str << qSetFieldWidth(tmp_width) << " "; 0068 str << qSetFieldWidth(5) << m_denominator; 0069 str.flush(); 0070 return str; 0071 } 0072 0073 /* return the numerator */ 0074 int Ratio::numerator() const 0075 { 0076 return m_numerator; 0077 } 0078 0079 /* return the denominator */ 0080 int Ratio::denominator() const 0081 { 0082 return m_denominator; 0083 } 0084 0085 /* set the numerator */ 0086 void Ratio::setNumerator(int pnumerator, bool reduce_it) 0087 { 0088 m_numerator = pnumerator; 0089 0090 // check, if we have to reduce the ratio 0091 if (reduce_it == true) 0092 reduce(); 0093 0094 return; 0095 } 0096 0097 /* set the denominator */ 0098 void Ratio::setDenominator(int pdenominator, bool reduce_it) 0099 { 0100 /* denominator is not allowed to be 0 */ 0101 if (!pdenominator) 0102 pdenominator = 1; 0103 0104 m_denominator = pdenominator; 0105 0106 // check, if we have to reduce the ratio 0107 if (reduce_it == true) 0108 reduce(); 0109 0110 return; 0111 } 0112 0113 /* set completely new ratio */ 0114 void Ratio::setRatio(int pnumerator, int pdenominator, bool reduce_it) 0115 { 0116 setNumerator(pnumerator, false); 0117 setDenominator(pdenominator, false); 0118 0119 // check, if we have to reduce the ratio 0120 if (reduce_it == true) { 0121 reduce(); 0122 } 0123 0124 return; 0125 } 0126 0127 /* set completely new ratio using mixed numbers */ 0128 void Ratio::setRatio(int pinteger, int pnumerator, int pdenominator, bool reduce_it) 0129 { 0130 // calculate new Numerator, but ignore negative values 0131 int newNumerator = qAbs(pinteger * pdenominator) + qAbs(pnumerator); 0132 0133 // restore negative values 0134 if ((pinteger < 0 || pnumerator < 0) && !(pinteger < 0 && pnumerator < 0)) 0135 newNumerator *= -1; 0136 0137 setRatio(newNumerator, pdenominator, reduce_it); 0138 0139 return; 0140 } 0141 0142 0143 /* add a ratio to a ratio like c = a + b */ 0144 Ratio Ratio::operator+ (const Ratio &addend) 0145 { 0146 // this object will be returned as the sum 0147 Ratio sum(0, 1); 0148 0149 // calculate and set the numerator without reducing 0150 sum.setNumerator(m_numerator * addend.denominator() 0151 + addend.numerator() * m_denominator, false); 0152 0153 // calculate and set the denominator without reducing 0154 sum.setDenominator(m_denominator * addend.denominator(), false); 0155 0156 // reduce the sum 0157 sum.reduce(); 0158 0159 return sum; 0160 } 0161 0162 /* sub a ratio from a ratio like c = a - b */ 0163 Ratio Ratio::operator- (Ratio subtrahend) 0164 { 0165 /* this object will be returned as the difference */ 0166 Ratio diff(0, 1); 0167 0168 /* change the sign of the subtrahend, so we can handle it as an addition */ 0169 subtrahend.change_sign(); 0170 diff = operator+ (subtrahend); 0171 0172 /* we have to change the sign back, so everything will be as before */ 0173 subtrahend.change_sign(); 0174 0175 /* return the difference */ 0176 return diff; 0177 } 0178 0179 /* mul a ratio with a ratio like c = a * b */ 0180 Ratio Ratio::operator*(const Ratio &factor) 0181 { 0182 // this object will be returned as the product 0183 Ratio product(0, 1); 0184 0185 // calculate and set numerator and denominator without reducing 0186 product.setNumerator(m_numerator * factor.numerator(), false); 0187 product.setDenominator(m_denominator * factor.denominator(), false); 0188 0189 // reduce the product 0190 product.reduce(); 0191 0192 return product; 0193 } 0194 0195 /* div a ratio with a ratio like c = a / b */ 0196 Ratio Ratio::operator/ (Ratio divisor) 0197 { 0198 /* this object will be returned as the quotient */ 0199 Ratio quotient(0, 1); 0200 0201 /* exchange numerator and denominator so we can handle as multiplication */ 0202 divisor.reziproc(); 0203 quotient = operator* (divisor); 0204 0205 /* go back to the original state */ 0206 divisor.reziproc(); 0207 0208 return quotient; 0209 } 0210 0211 /* we need this for initialization during a function prototyp; 0212 * ratio fraction = 0 */ 0213 Ratio Ratio::operator= (int dummy) 0214 { 0215 m_numerator = dummy; 0216 m_denominator = 1; 0217 0218 return *this; 0219 } 0220 0221 /* check, if the ratios are equivalent; -1/2 == 1/-2 -> true */ 0222 bool Ratio::operator== (const Ratio &right) 0223 { 0224 signed short orig_sign = 1, right_sign = 1; 0225 0226 /* we do not check the presign at this point */ 0227 if (qAbs(m_numerator) != qAbs(right.numerator())) 0228 return false; 0229 if (qAbs(m_denominator) != qAbs(right.denominator())) 0230 return false; 0231 0232 /* check if the signs of the ratios are equivalent */ 0233 if (m_numerator < 0) 0234 orig_sign = -1; 0235 if (m_denominator < 0) 0236 orig_sign *= -1; 0237 if (right.numerator() < 0) 0238 right_sign = -1; 0239 if (right.denominator() < 0) 0240 right_sign *= -1; 0241 0242 if (orig_sign != right_sign) 0243 return false; 0244 0245 return true; 0246 } 0247 0248 bool Ratio::operator< (const Ratio &right) 0249 { 0250 signed short sign = 1; 0251 Ratio tmp_ratio = Ratio(m_numerator, m_denominator) - right; 0252 0253 // check for this == right 0254 if (tmp_ratio == Ratio(0, 1)) 0255 return false; 0256 0257 // get the presign of the diff 0258 if (tmp_ratio.numerator() < 0) 0259 sign = -1; 0260 if (tmp_ratio.denominator() < 0) 0261 sign *= -1; 0262 0263 // if the diff is negative, this is smaller than right 0264 if (sign > 0) { 0265 return false; 0266 } else { 0267 return true; 0268 } 0269 } 0270 0271 bool Ratio::operator> (const Ratio &right) 0272 { 0273 signed short sign = 1; 0274 Ratio tmp_ratio = Ratio(m_numerator, m_denominator) - right; 0275 0276 // check for this == right 0277 if (tmp_ratio == Ratio(0, 1)) 0278 return false; 0279 0280 // get the presign of the diff 0281 if (tmp_ratio.numerator() < 0) 0282 sign = -1; 0283 if (tmp_ratio.denominator() < 0) 0284 sign *= -1; 0285 0286 // if the diff is positive, this is smaller than right 0287 if (sign < 0) { 0288 return false; 0289 } else { 0290 return true; 0291 } 0292 } 0293 0294 /* ----- private member functions ----- */ 0295 0296 /* reduce the ratio */ 0297 void Ratio::reduce() 0298 { 0299 /* we try prime numbers as divisors; I think it is the fastest way to do */ 0300 PrimeNumber number; 0301 short sign_numerator = 0, sign_denominator = 0; 0302 0303 /* make the whole ratio positive; save the signs; it is easier to reduce 0304 * the ratio, if it is positive */ 0305 if (m_numerator < 0) { // save numerator sign 0306 sign_numerator = 1; 0307 m_numerator *= -1; 0308 } 0309 if (m_denominator < 0) { // save denominator sign 0310 sign_denominator = 1; 0311 m_denominator *= -1; 0312 } 0313 0314 for (int divisor = number.get_first(); 0315 divisor <= m_numerator && divisor <= m_denominator; divisor = number.get_next()) { 0316 if (divisor == 0) { 0317 #ifdef DEBUG 0318 qDebug() << "ratio::reduce() -> divisor == 0 !!!"; 0319 qDebug() << "m_numerator: " << m_numerator; 0320 qDebug() << "m_denominator: " << m_denominator; 0321 // cin.get(); 0322 #endif 0323 /* so that the application does not crash with a floating 0324 * point exception; the error should not appear, but in some 0325 * cases it does and I do not know why */ 0326 continue; 0327 } 0328 0329 /* is the prime number a divisor of numerator and denominator? */ 0330 if ((m_numerator % divisor == 0) && (m_denominator % divisor == 0)) { 0331 /* reduce the ratio by the divisor */ 0332 m_numerator /= divisor; 0333 m_denominator /= divisor; 0334 0335 /* we have to go recursive, if the 2 is a divisor, because there 0336 * is no way to step one number before 2 -> there is no prime 0337 * number smaller than 2 */ 0338 if (divisor == 2) 0339 reduce(); 0340 else 0341 number.move_back(); // the prime number could be a divisor again 0342 } // if ((zaehler % divisor == 0) && (nenner % divisor == 0)) 0343 } // for (unsigned int divisor = number.get_first(); ... 0344 0345 /* restore the correct signs */ 0346 if (sign_numerator) 0347 m_numerator *= -1; 0348 if (sign_denominator) 0349 m_denominator *= -1; 0350 if (m_numerator == 0) 0351 m_denominator = 1; 0352 0353 return; 0354 } 0355 0356 /* exchange numerator and denominator */ 0357 void Ratio::reziproc() 0358 { 0359 int temp = m_numerator; 0360 m_numerator = m_denominator; 0361 m_denominator = temp; 0362 0363 return; 0364 } 0365 0366 /* ------ private member functions ------ */ 0367 0368 /* change the sign of the ratio; ratio = ratio * -1 */ 0369 void Ratio::change_sign() 0370 { 0371 /* this would be enough to change the sign of the ratio */ 0372 m_numerator *= -1; 0373 0374 /* if numerator and denominator both are negative, make them positive; 0375 * if denominator is negative and numerator positive, exchange the sign */ 0376 if ((m_numerator < 0 && m_denominator < 0) || (m_numerator > 0 && m_denominator < 0)) { 0377 m_numerator *= -1; 0378 m_denominator *= -1; 0379 } 0380 0381 return; 0382 } 0383 0384 0385 /* ------ some prototyps of non class functions ------ */ 0386 0387 // it is possible to stram ratio_object 0388 QTextStream & operator<< (QTextStream & str, const Ratio & pratio) 0389 { 0390 return pratio.display(str); 0391 }