2021-09-17 12:32:14 +02:00
|
|
|
#include "fraction.hpp"
|
2021-09-17 11:59:28 +02:00
|
|
|
|
2021-09-17 14:47:29 +02:00
|
|
|
namespace FractionNS {
|
|
|
|
|
|
|
|
int gcd(int p, int q) {
|
2021-09-20 16:34:45 +02:00
|
|
|
if(p < 0) p = -p;
|
|
|
|
if(q < 0) q = -q;
|
2021-09-17 14:47:29 +02:00
|
|
|
while(true) {
|
2021-09-20 16:34:45 +02:00
|
|
|
if(p == 0) return q;
|
|
|
|
q %= p;
|
|
|
|
if(q == 0) return p;
|
|
|
|
p %= q;
|
|
|
|
}
|
2021-09-17 14:47:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int lcm(int p, int q) {
|
|
|
|
int gcd = FractionNS::gcd(p, q);
|
|
|
|
|
|
|
|
return gcd != 0 ? (p / gcd * q) : 0;
|
|
|
|
}
|
|
|
|
|
2021-09-20 16:34:45 +02:00
|
|
|
void Fraction::reduce()
|
|
|
|
{
|
|
|
|
auto gcd = FractionNS::gcd(m_numerator, m_denominator);
|
|
|
|
if((gcd == 1 && m_denominator >= 0) || gcd == 0) return;
|
2021-09-17 14:47:29 +02:00
|
|
|
|
2021-09-20 16:34:45 +02:00
|
|
|
if(gcd == 1 && m_denominator < 0) {
|
|
|
|
m_numerator = -m_numerator;
|
|
|
|
m_denominator = -m_denominator;
|
|
|
|
}
|
|
|
|
else if(m_denominator < 0)
|
|
|
|
{
|
|
|
|
m_numerator = -m_numerator / gcd;
|
|
|
|
m_denominator = -m_denominator / gcd;
|
|
|
|
} else {
|
|
|
|
m_numerator /= gcd;
|
|
|
|
m_denominator /= gcd;
|
|
|
|
}
|
|
|
|
}
|
2021-09-17 14:47:29 +02:00
|
|
|
|
|
|
|
Fraction::Fraction(int numerator, int denominator)
|
|
|
|
{
|
2021-09-20 16:34:45 +02:00
|
|
|
if(denominator == 0) throw std::range_error("Tried to divide by 0.");
|
|
|
|
this->m_numerator = numerator;
|
|
|
|
this->m_denominator = denominator;
|
|
|
|
reduce();
|
2021-09-17 14:47:29 +02:00
|
|
|
}
|
2021-09-20 16:34:45 +02:00
|
|
|
Fraction::Fraction(const int n) {
|
2021-09-17 14:52:24 +02:00
|
|
|
this->m_numerator = n;
|
|
|
|
this->m_denominator = 1;
|
|
|
|
}
|
|
|
|
Fraction::Fraction(const Fraction& n) {
|
|
|
|
this->m_numerator = n.getNumerator();
|
|
|
|
this->m_denominator = n.getDenominator();
|
|
|
|
}
|
2021-09-17 14:47:29 +02:00
|
|
|
|
|
|
|
int Fraction::getNumerator() const { return m_numerator; }
|
|
|
|
int Fraction::getDenominator() const { return m_denominator; }
|
|
|
|
|
|
|
|
void Fraction::setNumerator(int numerator) {
|
2021-09-20 16:34:45 +02:00
|
|
|
auto gcd = FractionNS::gcd(numerator, this->m_denominator);
|
2021-09-17 14:47:29 +02:00
|
|
|
this->m_numerator = numerator / gcd;
|
|
|
|
}
|
|
|
|
void Fraction::setDenominator(int denominator) {
|
2021-09-20 16:34:45 +02:00
|
|
|
if(denominator == 0) throw std::range_error("Tried to divide by 0.");
|
|
|
|
auto gcd = FractionNS::gcd(this->m_numerator, denominator);
|
2021-09-17 14:47:29 +02:00
|
|
|
this->m_denominator = denominator / gcd;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString Fraction::display() const {
|
|
|
|
return QString::number(m_numerator) + '/' + QString::number(m_denominator);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Fraction::operator==(const int n) const {
|
|
|
|
return (double(m_numerator) / double(m_denominator)) == n;
|
|
|
|
}
|
|
|
|
bool Fraction::operator==(const float n) const {
|
2021-09-20 16:34:45 +02:00
|
|
|
return (float(m_numerator) / float(m_denominator)) == n;
|
2021-09-17 14:47:29 +02:00
|
|
|
}
|
|
|
|
bool Fraction::operator==(const double n) const {
|
|
|
|
return (double(m_numerator) / double(m_denominator)) == n;
|
|
|
|
}
|
|
|
|
bool Fraction::operator==(const Fraction& n) const {
|
|
|
|
return (this->m_numerator == n.getNumerator())
|
|
|
|
&& (this->m_denominator == n.getDenominator());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Fraction::operator!=(const int n) const {
|
|
|
|
return (double(m_numerator) / double(m_denominator)) != n;
|
|
|
|
}
|
|
|
|
bool Fraction::operator!=(const float n) const {
|
|
|
|
return (double(m_numerator) / double(m_denominator)) != n;
|
|
|
|
}
|
|
|
|
bool Fraction::operator!=(const double n) const {
|
|
|
|
return (double(m_numerator) / double(m_denominator)) != n;
|
|
|
|
}
|
|
|
|
bool Fraction::operator!=(const Fraction& n) const {
|
|
|
|
return (this->m_numerator != n.getNumerator())
|
|
|
|
|| (this->m_denominator != n.getDenominator());
|
|
|
|
}
|
|
|
|
|
|
|
|
Fraction& Fraction::operator+(const int n) const {
|
2021-09-20 16:34:45 +02:00
|
|
|
auto newNumerator = m_numerator + (n * m_denominator);
|
|
|
|
return *new Fraction(newNumerator, m_denominator);
|
2021-09-17 14:47:29 +02:00
|
|
|
}
|
2021-09-20 16:34:45 +02:00
|
|
|
Fraction& Fraction::operator+(const Fraction& other) const {
|
|
|
|
auto lcm = FractionNS::lcm(m_denominator, other.getDenominator());
|
|
|
|
|
|
|
|
auto ownNumeratorPart = m_numerator * (lcm / m_denominator);
|
|
|
|
auto otherNumeratorPart = other.getNumerator() * (lcm / other.getDenominator());
|
|
|
|
|
|
|
|
return *new Fraction(ownNumeratorPart + otherNumeratorPart, lcm);
|
2021-09-17 14:47:29 +02:00
|
|
|
}
|
2021-09-20 16:34:45 +02:00
|
|
|
|
|
|
|
Fraction& Fraction::operator+=(const int other) {
|
|
|
|
this->m_numerator = m_numerator + (other * m_denominator);
|
|
|
|
reduce();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
Fraction& Fraction::operator+=(const Fraction& other) {
|
|
|
|
// Sanity check for Clang
|
|
|
|
// Not strictly necessary since setting to 0 is checked against in setDenominator and constructor(s).
|
|
|
|
if(other.getDenominator() == 0) return *this;
|
|
|
|
|
|
|
|
auto lcm = FractionNS::lcm(m_denominator, other.getDenominator());
|
|
|
|
|
|
|
|
auto ownNumeratorPart = m_numerator * (lcm / m_denominator);
|
|
|
|
auto otherNumeratorPart = other.getNumerator() * (lcm / other.getDenominator());
|
|
|
|
|
|
|
|
this->m_numerator = ownNumeratorPart + otherNumeratorPart;
|
|
|
|
this->m_denominator = lcm;
|
|
|
|
|
|
|
|
reduce();
|
|
|
|
return *this;
|
2021-09-17 14:47:29 +02:00
|
|
|
}
|
2021-09-20 16:34:45 +02:00
|
|
|
|
|
|
|
Fraction& Fraction::operator-(const int n) const {
|
|
|
|
auto newNumerator = m_numerator - (n * m_denominator);
|
|
|
|
return *new Fraction(newNumerator, m_denominator);
|
|
|
|
};
|
|
|
|
Fraction& Fraction::operator-(const Fraction& other) const {
|
|
|
|
auto lcm = FractionNS::lcm(m_denominator, other.getDenominator());
|
|
|
|
|
|
|
|
auto ownNumeratorPart = m_numerator * (lcm / m_denominator);
|
|
|
|
auto otherNumeratorPart = other.getNumerator() * (lcm / other.getDenominator());
|
|
|
|
|
|
|
|
return *new Fraction(ownNumeratorPart - otherNumeratorPart, lcm);
|
|
|
|
}
|
|
|
|
|
|
|
|
Fraction& Fraction::operator-=(const int n) {
|
|
|
|
auto newNumerator = m_numerator - (n * m_denominator);
|
|
|
|
return *new Fraction(newNumerator, m_denominator);
|
|
|
|
};
|
|
|
|
Fraction& Fraction::operator-=(const Fraction& other) {
|
|
|
|
// Sanity check for Clang
|
|
|
|
// Not strictly necessary since setting to 0 is checked against in setDenominator and constructor(s).
|
|
|
|
if(other.getDenominator() == 0) return *this;
|
|
|
|
auto lcm = FractionNS::lcm(m_denominator, other.getDenominator());
|
|
|
|
|
|
|
|
auto ownNumeratorPart = m_numerator * (lcm / m_denominator);
|
|
|
|
auto otherNumeratorPart = other.getNumerator() * (lcm / other.getDenominator());
|
|
|
|
|
|
|
|
return *new Fraction(ownNumeratorPart - otherNumeratorPart, lcm);
|
2021-09-17 14:47:29 +02:00
|
|
|
}
|
2021-09-17 11:59:28 +02:00
|
|
|
}
|