#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 std::range_error("Tried to divide by 0."); 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 std::range_error("Tried to divide by 0."); 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& n) const { return (this->m_numerator != n.getNumerator()) || (this->m_denominator != n.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; } }