2021-09-17 12:32:14 +02:00
|
|
|
#include "fraction.hpp"
|
2021-09-17 11:59:28 +02:00
|
|
|
|
2021-09-21 11:42:53 +02:00
|
|
|
#include <QtMath>
|
2021-09-17 14:47:29 +02:00
|
|
|
|
2021-09-21 11:42:53 +02:00
|
|
|
namespace FractionNS {
|
2021-09-17 14:47:29 +02:00
|
|
|
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-21 10:42:04 +02:00
|
|
|
if(denominator == 0) throw divide_by_zero_error();
|
2021-09-20 16:34:45 +02:00
|
|
|
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-21 10:42:04 +02:00
|
|
|
if(denominator == 0) throw divide_by_zero_error();
|
2021-09-20 16:34:45 +02:00
|
|
|
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);
|
|
|
|
}
|
2021-09-21 11:40:44 +02:00
|
|
|
Fraction& Fraction::inv() const {
|
|
|
|
return *new Fraction(m_denominator, m_numerator);
|
|
|
|
}
|
|
|
|
|
|
|
|
float Fraction::toFloat() const { return float(m_numerator) / m_denominator; }
|
|
|
|
double Fraction::toDouble() const { return double(m_numerator) / m_denominator; }
|
2021-09-17 14:47:29 +02:00
|
|
|
|
|
|
|
bool Fraction::operator==(const int n) const {
|
2021-09-21 11:41:35 +02:00
|
|
|
return m_denominator == 1
|
|
|
|
&& m_numerator == n;
|
2021-09-17 14:47:29 +02:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
2021-09-21 09:22:46 +02:00
|
|
|
bool Fraction::operator==(const Fraction& other) const {
|
|
|
|
return (this->m_numerator == other.getNumerator())
|
|
|
|
&& (this->m_denominator == other.getDenominator());
|
2021-09-17 14:47:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2021-09-21 09:42:07 +02:00
|
|
|
bool Fraction::operator!=(const Fraction& other) const {
|
|
|
|
return (this->m_numerator != other.getNumerator())
|
|
|
|
|| (this->m_denominator != other.getDenominator());
|
2021-09-17 14:47:29 +02:00
|
|
|
}
|
|
|
|
|
2021-09-21 10:03:45 +02:00
|
|
|
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()));
|
|
|
|
}
|
|
|
|
|
2021-09-21 10:12:20 +02:00
|
|
|
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()));
|
|
|
|
}
|
|
|
|
|
2021-09-21 10:03:45 +02:00
|
|
|
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()));
|
|
|
|
}
|
|
|
|
|
2021-09-21 10:12:20 +02:00
|
|
|
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()));
|
|
|
|
}
|
|
|
|
|
2021-09-17 14:47:29 +02:00
|
|
|
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
|
|
|
|
2021-09-21 09:22:46 +02:00
|
|
|
Fraction& Fraction::operator+=(const int n) {
|
|
|
|
this->m_numerator = m_numerator + (n * m_denominator);
|
2021-09-20 16:34:45 +02:00
|
|
|
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) {
|
2021-09-21 09:22:46 +02:00
|
|
|
m_numerator -= n * m_denominator;
|
|
|
|
return *this;
|
2021-09-20 16:34:45 +02:00
|
|
|
};
|
|
|
|
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());
|
|
|
|
|
2021-09-21 09:22:46 +02:00
|
|
|
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;
|
2021-09-17 14:47:29 +02:00
|
|
|
}
|
2021-09-21 09:30:49 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2021-09-21 10:03:45 +02:00
|
|
|
|
2021-09-21 11:42:53 +02:00
|
|
|
double Fraction::pow(const int n) const {
|
|
|
|
if(n == 0) {
|
|
|
|
if(m_numerator == 0) {
|
|
|
|
throw not_defined_error();
|
|
|
|
}
|
|
|
|
return 1.0;
|
|
|
|
}
|
|
|
|
if(n < 0) {
|
|
|
|
if(m_numerator == 0) {
|
|
|
|
throw not_real_error();
|
|
|
|
}
|
|
|
|
if(n == -1) {
|
|
|
|
return double(m_denominator) / m_numerator;
|
|
|
|
}
|
|
|
|
|
|
|
|
return qPow(double(m_denominator) / m_numerator, -n);
|
|
|
|
}
|
|
|
|
return qPow(double(m_numerator) / m_denominator, n);
|
|
|
|
}
|
|
|
|
double Fraction::pow(const Fraction& other) const {
|
|
|
|
if(other == 0) {
|
|
|
|
if(m_numerator == 0) {
|
|
|
|
throw not_defined_error();
|
|
|
|
}
|
|
|
|
return 1.0;
|
|
|
|
}
|
|
|
|
if(other < 0) {
|
|
|
|
if(m_numerator == 0) {
|
|
|
|
throw not_real_error();
|
|
|
|
}
|
|
|
|
if(other == -1) {
|
|
|
|
return double(m_denominator) / m_numerator;
|
|
|
|
}
|
|
|
|
return qPow(double(m_denominator) / m_numerator, -other.toDouble());
|
|
|
|
}
|
|
|
|
return qPow(double(m_numerator) / m_denominator, other.toDouble());
|
|
|
|
}
|
|
|
|
|
2021-09-21 10:03:45 +02:00
|
|
|
Fraction& Fraction::operator-() const {
|
|
|
|
return *new Fraction(-m_numerator, m_denominator);
|
|
|
|
}
|
|
|
|
Fraction& Fraction::operator+() const {
|
|
|
|
return *new Fraction(m_numerator, m_denominator);
|
|
|
|
}
|
2021-09-17 11:59:28 +02:00
|
|
|
}
|