#include "fraction.hpp" namespace FractionNS { int gcd(int p, int q) { if(p < 0) p = -p; if(q < 0) q = -q; while(true) { if(p == 0) return q; q %= p; if(q == 0) return p; p %= q; } } int lcm(int p, int q) { int gcd = FractionNS::gcd(p, q); return gcd != 0 ? (p / gcd * q) : 0; } void Fraction::reduce() { auto gcd = FractionNS::gcd(m_numerator, m_denominator); if((gcd == 1 && m_denominator >= 0) || gcd == 0) return; 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; } } Fraction::Fraction(int numerator, int denominator) { if(denominator == 0) throw divide_by_zero_error(); this->m_numerator = numerator; this->m_denominator = denominator; reduce(); } Fraction::Fraction(const int n) { this->m_numerator = n; this->m_denominator = 1; } Fraction::Fraction(const Fraction& n) { this->m_numerator = n.getNumerator(); this->m_denominator = n.getDenominator(); } int Fraction::getNumerator() const { return m_numerator; } int Fraction::getDenominator() const { return m_denominator; } void Fraction::setNumerator(int numerator) { auto gcd = FractionNS::gcd(numerator, this->m_denominator); this->m_numerator = numerator / gcd; } void Fraction::setDenominator(int denominator) { if(denominator == 0) throw divide_by_zero_error(); auto gcd = FractionNS::gcd(this->m_numerator, denominator); 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 { return (float(m_numerator) / float(m_denominator)) == n; } bool Fraction::operator==(const double n) const { return (double(m_numerator) / double(m_denominator)) == n; } bool Fraction::operator==(const Fraction& other) const { return (this->m_numerator == other.getNumerator()) && (this->m_denominator == other.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& other) const { return (this->m_numerator != other.getNumerator()) || (this->m_denominator != other.getDenominator()); } bool Fraction::operator<(const int n) const { return m_numerator < n * m_denominator; } bool Fraction::operator<(const float n) const { return m_numerator < n * m_denominator; } bool Fraction::operator<(const double n) const { return m_numerator < n * m_denominator; } bool Fraction::operator<(const Fraction& other) const { auto lcm = FractionNS::lcm(m_denominator, other.getDenominator()); return (m_numerator * (lcm / m_denominator)) < (other.getNumerator() * (lcm / other.getDenominator())); } bool Fraction::operator<=(const int n) const { return m_numerator <= n * m_denominator; } bool Fraction::operator<=(const float n) const { return m_numerator <= n * m_denominator; } bool Fraction::operator<=(const double n) const { return m_numerator <= n * m_denominator; } bool Fraction::operator<=(const Fraction& other) const { auto lcm = FractionNS::lcm(m_denominator, other.getDenominator()); return (m_numerator * (lcm / m_denominator)) <= (other.getNumerator() * (lcm / other.getDenominator())); } bool Fraction::operator>(const int n) const { return m_numerator > n * m_denominator; } bool Fraction::operator>(const float n) const { return m_numerator > n * m_denominator; } bool Fraction::operator>(const double n) const { return m_numerator > n * m_denominator; } bool Fraction::operator>(const Fraction& other) const { auto lcm = FractionNS::lcm(m_denominator, other.getDenominator()); return (m_numerator * (lcm / m_denominator)) > (other.getNumerator() * (lcm / other.getDenominator())); } bool Fraction::operator>=(const int n) const { return m_numerator >= n * m_denominator; } bool Fraction::operator>=(const float n) const { return m_numerator >= n * m_denominator; } bool Fraction::operator>=(const double n) const { return m_numerator >= n * m_denominator; } bool Fraction::operator>=(const Fraction& other) const { auto lcm = FractionNS::lcm(m_denominator, other.getDenominator()); return (m_numerator * (lcm / m_denominator)) >= (other.getNumerator() * (lcm / other.getDenominator())); } 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) { this->m_numerator = m_numerator + (n * 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; } 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) { m_numerator -= n * m_denominator; 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()); m_numerator = ownNumeratorPart - otherNumeratorPart; m_denominator = lcm; reduce(); return *this; } Fraction& Fraction::operator*(const int n) const { return *new Fraction(m_numerator * n, m_denominator); } Fraction& Fraction::operator*(const Fraction& other) const { return *new Fraction(m_numerator * other.getNumerator(), m_denominator * other.getDenominator()); } Fraction& Fraction::operator*=(const int n) { m_numerator *= n; return *this; } Fraction& Fraction::operator*=(const Fraction& other) { m_numerator *= other.getNumerator(); m_denominator *= other.getDenominator(); reduce(); return *this; } Fraction& Fraction::operator/(const int n) const { return *new Fraction(m_numerator, m_denominator * n); } Fraction& Fraction::operator/(const Fraction& other) const { return *new Fraction(m_numerator * other.getDenominator(), m_denominator * other.getNumerator()); } Fraction& Fraction::operator/=(const int n) { m_denominator *= n; reduce(); return *this; } Fraction& Fraction::operator/=(const Fraction& other) { m_numerator *= other.getDenominator(); m_denominator *= other.getNumerator(); reduce(); return *this; } Fraction& Fraction::operator-() const { return *new Fraction(-m_numerator, m_denominator); } Fraction& Fraction::operator+() const { return *new Fraction(m_numerator, m_denominator); } }