You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
369 lines
8.8 KiB
C++
369 lines
8.8 KiB
C++
/***************************************************************************
|
|
ratio.cpp - source code of class ratio
|
|
-------------------
|
|
begin : Tue Nov 27 16:40:42 CET 2001
|
|
copyright : (C) 2001-2004 by Sebastian Stein
|
|
email : seb.kde@hpfsc.de
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include "ratio.h"
|
|
#include "primenumber.h"
|
|
|
|
/* ----- public member functions ----- */
|
|
|
|
/* constructor */
|
|
ratio::ratio(int pnumerator, int pdenominator):m_numerator(pnumerator), m_denominator(pdenominator)
|
|
{
|
|
#ifdef DEBUG
|
|
kdDebug() << "constructor ratio" << endl;
|
|
#endif
|
|
|
|
// denominator is never allowed to be 0
|
|
if (!m_denominator)
|
|
m_denominator = 1;
|
|
|
|
// reduce the new ratio
|
|
reduce();
|
|
}
|
|
|
|
/* copy constructor */
|
|
ratio::ratio(const ratio & copy_ratio)
|
|
{
|
|
#ifdef DEBUG
|
|
kdDebug() << "copy constructor ratio" << endl;
|
|
#endif
|
|
|
|
setNumerator(copy_ratio.numerator(), false);
|
|
setDenominator(copy_ratio.denominator(), false);
|
|
}
|
|
|
|
/* destructor */
|
|
ratio::~ratio()
|
|
{
|
|
#ifdef DEBUG
|
|
kdDebug() << "destructor ratio" << endl;
|
|
#endif
|
|
}
|
|
|
|
/* displays the ratio on stdout; just for debugging */
|
|
TQTextStream & ratio::display(TQTextStream & str) const
|
|
{
|
|
int tmp_width = str.width();
|
|
str << qSetW(5) << " ";
|
|
str << qSetW(5) << m_numerator << endl;
|
|
str << qSetW(tmp_width) << " ";
|
|
str << " ----- " << endl;
|
|
str << qSetW(tmp_width) << " ";
|
|
return str << qSetW(5) << m_denominator;
|
|
}
|
|
|
|
/* return the numerator */
|
|
int ratio::numerator() const
|
|
{
|
|
return m_numerator;
|
|
}
|
|
|
|
/* return the denominator */
|
|
int ratio::denominator() const
|
|
{
|
|
return m_denominator;
|
|
}
|
|
|
|
/* set the numerator */
|
|
void ratio::setNumerator(int pnumerator, bool reduce_it)
|
|
{
|
|
m_numerator = pnumerator;
|
|
|
|
// check, if we have to reduce the ratio
|
|
if (reduce_it == true)
|
|
reduce();
|
|
|
|
return;
|
|
}
|
|
|
|
/* set the denominator */
|
|
void ratio::setDenominator(int pdenominator, bool reduce_it)
|
|
{
|
|
/* denominator is not allowed to be 0 */
|
|
if (!pdenominator)
|
|
pdenominator = 1;
|
|
|
|
m_denominator = pdenominator;
|
|
|
|
// check, if we have to reduce the ratio
|
|
if (reduce_it == true)
|
|
reduce();
|
|
|
|
return;
|
|
}
|
|
|
|
/* add a ratio to a ratio like c = a + b */
|
|
ratio ratio::operator+(ratio addend)
|
|
{
|
|
// this object will be returned as the sum
|
|
ratio sum(0, 1);
|
|
|
|
// calculate and set the numerator without reducing
|
|
sum.setNumerator(m_numerator * addend.denominator()
|
|
+ addend.numerator() * m_denominator, false);
|
|
|
|
// calculate and set the denominator without reducing
|
|
sum.setDenominator(m_denominator * addend.denominator(), false);
|
|
|
|
// reduce the sum
|
|
sum.reduce();
|
|
|
|
return sum;
|
|
}
|
|
|
|
/* sub a ratio from a ratio like c = a - b */
|
|
ratio ratio::operator-(ratio subtrahend)
|
|
{
|
|
/* this object will be returned as the difference */
|
|
ratio diff(0, 1);
|
|
|
|
/* change the sign of the subtrahend, so we can handle it as an addition */
|
|
subtrahend.change_sign();
|
|
diff = operator+(subtrahend);
|
|
|
|
/* we have to change the sign back, so everything will be as before */
|
|
subtrahend.change_sign();
|
|
|
|
/* return the difference */
|
|
return diff;
|
|
}
|
|
|
|
/* mul a ratio with a ratio like c = a * b */
|
|
ratio ratio::operator*(ratio factor)
|
|
{
|
|
// this object will be returned as the product
|
|
ratio product(0, 1);
|
|
|
|
// calculate and set numerator and denominator without reducing
|
|
product.setNumerator(m_numerator * factor.numerator(), false);
|
|
product.setDenominator(m_denominator * factor.denominator(), false);
|
|
|
|
// reduce the product
|
|
product.reduce();
|
|
|
|
return product;
|
|
}
|
|
|
|
/* div a ratio with a ratio like c = a / b */
|
|
ratio ratio::operator/(ratio divisor)
|
|
{
|
|
/* this object will be returned as the quotient */
|
|
ratio quotient(0, 1);
|
|
|
|
/* exchange numerator and denominator so we can handle as multiplication */
|
|
divisor.reziproc();
|
|
quotient = operator*(divisor);
|
|
|
|
/* go back to the original state */
|
|
divisor.reziproc();
|
|
|
|
return quotient;
|
|
}
|
|
|
|
/* we need this for initialization during a function prototyp;
|
|
* ratio fraction = 0 */
|
|
ratio ratio::operator=(int dummy)
|
|
{
|
|
m_numerator = dummy;
|
|
m_denominator = 1;
|
|
|
|
return *this;
|
|
}
|
|
|
|
/* check, if the ratios are equivalent; -1/2 == 1/-2 -> TRUE */
|
|
bool ratio::operator==(ratio right)
|
|
{
|
|
signed short orig_sign = 1, right_sign = 1;
|
|
|
|
/* we do not check the presign at this point */
|
|
if (TQABS(m_numerator) != TQABS(right.numerator()))
|
|
return false;
|
|
if (TQABS(m_denominator) != TQABS(right.denominator()))
|
|
return false;
|
|
|
|
/* check if the signs of the ratios are equivalent */
|
|
if (m_numerator < 0)
|
|
orig_sign = -1;
|
|
if (m_denominator < 0)
|
|
orig_sign *= -1;
|
|
if (right.numerator() < 0)
|
|
right_sign = -1;
|
|
if (right.denominator() < 0)
|
|
right_sign *= -1;
|
|
|
|
if (orig_sign != right_sign)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ratio::operator<(ratio right)
|
|
{
|
|
signed short sign = 1;
|
|
ratio tmp_ratio = ratio(m_numerator, m_denominator) - right;
|
|
|
|
// check for this == right
|
|
if (tmp_ratio == ratio(0, 1))
|
|
return false;
|
|
|
|
// get the presign of the diff
|
|
if (tmp_ratio.numerator() < 0)
|
|
sign = -1;
|
|
if (tmp_ratio.denominator() < 0)
|
|
sign *= -1;
|
|
|
|
// if the diff is negative, this is smaller then right
|
|
if (sign > 0)
|
|
{
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool ratio::operator>(ratio right)
|
|
{
|
|
signed short sign = 1;
|
|
ratio tmp_ratio = ratio(m_numerator, m_denominator) - right;
|
|
|
|
// check for this == right
|
|
if (tmp_ratio == ratio(0, 1))
|
|
return false;
|
|
|
|
// get the presign of the diff
|
|
if (tmp_ratio.numerator() < 0)
|
|
sign = -1;
|
|
if (tmp_ratio.denominator() < 0)
|
|
sign *= -1;
|
|
|
|
// if the diff is positive, this is smaller then right
|
|
if (sign < 0)
|
|
{
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/* ----- private member functions ----- */
|
|
|
|
/* reduce the ratio */
|
|
void ratio::reduce()
|
|
{
|
|
/* we try prime numbers as divisors; I think it is the fastet way to do */
|
|
primenumber number;
|
|
short sign_numerator = 0, sign_denominator = 0;
|
|
|
|
/* make the whole ratio positive; save the signs; it is easier to reduce
|
|
* the ratio, if it is positive */
|
|
if (m_numerator < 0) // save numerator sign
|
|
{
|
|
sign_numerator = 1;
|
|
m_numerator *= -1;
|
|
}
|
|
if (m_denominator < 0) // save denominator sign
|
|
{
|
|
sign_denominator = 1;
|
|
m_denominator *= -1;
|
|
}
|
|
|
|
for (int divisor = number.get_first();
|
|
divisor <= m_numerator && divisor <= m_denominator; divisor = number.get_next())
|
|
{
|
|
if (divisor == 0)
|
|
{
|
|
#ifdef DEBUG
|
|
kdDebug() << "ratio::reduce() -> divisor == 0 !!!" << endl;
|
|
kdDebug() << "m_numerator: " << m_numerator << endl;
|
|
kdDebug() << "m_denominator: " << m_denominator << endl;
|
|
// cin.get();
|
|
#endif
|
|
/* so that the application does not crash with a floating
|
|
* point exception; the error should not appear, but in some
|
|
* cases it does and I do not know why */
|
|
continue;
|
|
}
|
|
|
|
/* is the prime number a divisor of numerator and denominator? */
|
|
if ((m_numerator % divisor == 0) && (m_denominator % divisor == 0))
|
|
{
|
|
/* reduce the ratio by the divisor */
|
|
m_numerator /= divisor;
|
|
m_denominator /= divisor;
|
|
|
|
/* we have to go recursive, if the 2 is a divisor, because there
|
|
* is no way to step one number before 2 -> there is no prime
|
|
* number smaller than 2 */
|
|
if (divisor == 2)
|
|
reduce();
|
|
else
|
|
number.move_back(); // the prime number could be a divisor again
|
|
} // if ((zaehler % divisor == 0) && (nenner % divisor == 0))
|
|
} // for (unsigned int divisor = number.get_first(); ...
|
|
|
|
/* restore the correct signs */
|
|
if (sign_numerator)
|
|
m_numerator *= -1;
|
|
if (sign_denominator)
|
|
m_denominator *= -1;
|
|
if (m_numerator == 0)
|
|
m_denominator = 1;
|
|
|
|
return;
|
|
}
|
|
|
|
/* exchange numerator and denominator */
|
|
void ratio::reziproc()
|
|
{
|
|
int temp = m_numerator;
|
|
m_numerator = m_denominator;
|
|
m_denominator = temp;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/* ------ private member functions ------ */
|
|
|
|
/* change the sign of the ratio; ratio = ratio * -1 */
|
|
void ratio::change_sign()
|
|
{
|
|
/* this would be enough to change the sign of the ratio */
|
|
m_numerator *= -1;
|
|
|
|
/* if numerator and denominator both are negative, make them positive;
|
|
* if denominator is negative and numerator positive, exchange the sign */
|
|
if ((m_numerator < 0 && m_denominator < 0) || (m_numerator > 0 && m_denominator < 0))
|
|
{
|
|
m_numerator *= -1;
|
|
m_denominator *= -1;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/* ------ some prototyps of non class functions ------ */
|
|
|
|
// it is possible to stram ratio_object
|
|
TQTextStream & operator<<(TQTextStream & str, const ratio & pratio)
|
|
{
|
|
return pratio.display(str);
|
|
}
|