diff --git a/app/common/rational.cpp b/app/common/rational.cpp index 552f298b9..28f88d2ba 100644 --- a/app/common/rational.cpp +++ b/app/common/rational.cpp @@ -1,412 +1,408 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ +//Copyright 2015 Adam Quintero +//This program is distributed under the terms of the GNU General Public License. #include "rational.h" -rational::rational(const int64_t &numerator) : - numerator_(numerator), - denominator_(1) -{ - if (numerator_ == 0) { - denominator_ = 0; - } -} - -rational::rational(const int64_t &numerator, const int64_t &denominator) : - numerator_(numerator), - denominator_(denominator) -{ - if (denominator_ != 0) { - - if (numerator_ != 0) { - FixSigns(); - Reduce(); - } else { - denominator_ = 0; - } - - } else { - numerator_ = 0; - } -} +int rational::activeInstances = 0; rational::rational(const AVRational &r) : - numerator_(r.num), - denominator_(r.den) + numer(r.num), + denom(r.den) { } -rational::rational(const rational &r) : - numerator_(r.numerator_), - denominator_(r.denominator_) +rational::~rational() { + activeInstances--; } -const rational &rational::operator=(const rational &r) -{ - if (this != &r) { - numerator_ = r.numerator_; - denominator_ = r.denominator_; - } +//Function: print number to cout +void rational::print(ostream &out) const +{ + out << this->numer << "/" << this->denom; +} + +//Function: ensures denom >= 0 + +void rational::fixSigns() +{ + if(denom < 0) + { + denom = -denom; + numer = -numer; + } + if(numer == intType(0) || denom == intType(0)) + { + numer = intType(0); + denom = intType(0); + } +} + +//Function: ensures lowest form + +void rational::reduce() +{ + intType d = 1; + + if(denom != 0 && numer !=0) + d = gcd(numer, denom); + + if(d > 1) + { + numer /= d; + denom /= d; + } +} + +//Function: finds greatest common denominator + +intType rational::gcd(intType &x, intType &y) +{ + if(y == 0) + return x; + else + { + intType tmp = x % y; + + return gcd(y, tmp); + } +} + +//Function: convert to double + +double rational::toDouble() const +{ + if(denom != 0) + return static_cast(numer) / static_cast(denom); + else + return static_cast(0); +} + +rational rational::flipped() const +{ + return rational(denom, numer); +} + +//Function: get active instances + +int rational::getActiveInstances() +{ + return activeInstances; +} + +const intType &rational::numerator() const +{ + return numer; +} + +const intType &rational::denominator() const +{ + return denom; +} + +//Assignment Operators + +const rational& rational::operator=(const rational &rhs) +{ + if(this != &rhs) + { + numer = rhs.numer; + denom = rhs.denom; + } return *this; } -const rational &rational::operator+=(const rational &r) +const rational& rational::operator+=(const rational &rhs) { - if (numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ == 0) { - numerator_ = 0; - denominator_ = 0; - } else { - if(numerator_ * denominator_ != 0 && r.numerator_ * r.denominator_ == 0) { - // The other rational == 0, no addition needs to be done - } else { - if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ != 0) + if(numer * denom == intType(0) && rhs.numer * rhs.denom == intType(0)) + { + numer = intType(0); + denom = intType(0); + } + else + if(numer * denom != intType(0) && rhs.numer * rhs.denom == intType(0)) { - numerator_ = r.numerator_; - denominator_ = r.denominator_; + } + else + if(numer * denom == intType(0) && rhs.numer * rhs.denom != intType(0)) + { + numer = rhs.numer; + denom = rhs.denom; + } else + { + numer = (numer * rhs.denom) + (rhs.numer * denom); + denom = denom * rhs.denom; + fixSigns(); + reduce(); + } + return *this; +} + +const rational& rational::operator-=(const rational &rhs) +{ + if(numer * denom == intType(0) && rhs.numer * rhs.denom == intType(0)) + { + numer = intType(0); + denom = intType(0); + } + else + if(numer * denom != intType(0) && rhs.numer * rhs.denom == intType(0)) { - numerator_ = (numerator_ * r.denominator_) + (r.numerator_ * denominator_); - denominator_ = denominator_ * r.denominator_; - FixSigns(); - Reduce(); + } - } - } - return *this; -} - -const rational &rational::operator-=(const rational &r) -{ - if(numerator_ * denominator_ == 0 && r.numerator_ * r.numerator_ == 0) { - numerator_ = 0; - denominator_ = 0; - } else { - if(numerator_ * denominator_ != 0 && r.numerator_ * r.denominator_ == 0) { - - } else { - if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ != 0) { - numerator_ = -(r.numerator_); - denominator_ = r.denominator_; - } else { - numerator_ = (numerator_ * r.denominator_) - (r.numerator_ * denominator_); - numerator_ = denominator_ * r.denominator_; - FixSigns(); - Reduce(); - } - } - } - return *this; -} - -const rational &rational::operator/=(const rational &r) -{ - numerator_ = numerator_ * r.denominator_; - denominator_ = denominator_ * r.numerator_; - FixSigns(); - Reduce(); - return *this; -} - -const rational &rational::operator*=(const rational &r) -{ - numerator_ = numerator_ * r.numerator_; - denominator_ = denominator_ * r.denominator_; - FixSigns(); - Reduce(); - return *this; -} - -rational rational::operator+(const rational &r) const -{ - rational result(*this); - result += r; - return result; -} - -rational rational::operator-(const rational &r) const -{ - rational result(*this); - result -= r; - return result; -} - -rational rational::operator/(const rational &r) const -{ - rational result(*this); - result /= r; - return result; -} - -rational rational::operator*(const rational &r) const -{ - rational result(*this); - result *= r; - return result; -} - -bool rational::operator<(const rational &r) const -{ - if (numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ == 0) { - return false; - } else { - if (numerator_ * denominator_ != 0 && r.numerator_ * r.denominator_ == 0) { - if(numerator_ * denominator_ < 0) - return true; + else + if(numer * denom == intType(0) && rhs.numer * rhs.denom != intType(0)) + { + numer = -(rhs.numer); + denom = rhs.denom; + } else - return false; - } - else { - if (numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ != 0) { - if (r.numerator_ * r.denominator_ < 0) { - return false; - } else { - return true; + { + numer = (numer * rhs.denom) - (rhs.numer * denom); + denom = denom * rhs.denom; + fixSigns(); + reduce(); } - } else { - return ((numerator_ * r.denominator_) < (denominator_ * r.numerator_)); - } - } - } + return *this; } -bool rational::operator<=(const rational &r) const +const rational& rational::operator/=(const rational &rhs) { - if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ == 0) { - return true; - } else { - if(numerator_ * denominator_ != 0 && r.numerator_ * r.denominator_ == 0) { - if(numerator_ * denominator_ < 0) { - return true; - } else { - return false; - } - } else { - if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ != 0) { - if(r.numerator_ * r.denominator_ < 0) { - return false; - } else { - return true; - } - } else { - return ((numerator_ * r.denominator_) <= (denominator_ * r.numerator_)); - } - } - } + numer = numer * rhs.denom; + denom = denom * rhs.numer; + fixSigns(); + reduce(); + return *this; } -bool rational::operator>(const rational &r) const +const rational& rational::operator*=(const rational &rhs) { - if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ == 0) { + numer = numer * rhs.numer; + denom = denom * rhs.denom; + fixSigns(); + reduce(); + return *this; +} + +//Binary math operators + +rational rational::operator+(const rational &rhs) const +{ + rational answer(*this); + answer += rhs; + return answer; +} + +rational rational::operator-(const rational &rhs) const +{ + rational answer(*this); + answer -= rhs; + return answer; +} + +rational rational::operator/(const rational &rhs) const +{ + rational answer(*this); + answer /= rhs; + return answer; +} + +rational rational::operator*(const rational &rhs) const +{ + rational answer(*this); + answer *= rhs; + return answer; +} + +//Relational and equality operators + +bool rational::operator<(const rational &rhs) const +{ + if(numer * denom == intType(0) && rhs.numer * rhs.denom == intType(0)) return false; - } else { - if(numerator_ * denominator_ != 0 && r.numerator_ * r.denominator_ == 0) { - if(numerator_ * denominator_ > 0) { - return true; - } else { - return false; - } - } else { - if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ != 0) { - if(r.numerator_ * r.denominator_ > 0) { - return false; - } else { + else + if(numer * denom != intType(0) && rhs.numer * rhs.denom == intType(0)) + { + if(numer * denom < intType(0)) return true; - } - } else { - return ((numerator_ * r.denominator_) > (denominator_ * r.numerator_)); + else + return false; } - } - } + else + if(numer * denom == intType(0) && rhs.numer * rhs.denom != intType(0)) + { + if(rhs.numer * rhs.denom < intType(0)) + return false; + else + return true; + } + else + return ((numer * rhs.denom) < (denom * rhs.numer)); } -bool rational::operator>=(const rational &r) const +bool rational::operator<=(const rational &rhs) const { - if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ == 0) { + if(numer * denom == intType(0) && rhs.numer * rhs.denom == intType(0)) return true; - } else { - if(numerator_ * denominator_ != 0 && r.numerator_ * r.denominator_ == 0) { - if(numerator_ * denominator_ > 0) { - return true; - } else { - return false; - } - } else { - if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ != 0) { - if(r.numerator_ * r.denominator_ > 0) { - return false; - } else { + else + if(numer * denom != intType(0) && rhs.numer * rhs.denom == intType(0)) + { + if(numer * denom < intType(0)) return true; - } - } else { - return ((numerator_ * r.denominator_) >= (denominator_ * r.numerator_)); + else + return false; } - } - } + else + if(numer * denom == intType(0) && rhs.numer * rhs.denom != intType(0)) + { + if(rhs.numer * rhs.denom < intType(0)) + return false; + else + return true; + } + else + return ((numer * rhs.denom) <= (denom * rhs.numer)); } -bool rational::operator==(const rational &r) const +bool rational::operator>(const rational &rhs) const { - return (numerator_ == r.numerator_ && denominator_ == r.denominator_); + if(numer * denom == intType(0) && rhs.numer * rhs.denom == intType(0)) + return false; + else + if(numer * denom != intType(0) && rhs.numer * rhs.denom == intType(0)) + { + if(numer * denom > intType(0)) + return true; + else + return false; + } + else + if(numer * denom == intType(0) && rhs.numer * rhs.denom != intType(0)) + { + if(rhs.numer * rhs.denom > intType(0)) + return false; + else + return true; + } + else + return ((numer * rhs.denom) > (denom * rhs.numer)); } -bool rational::operator!=(const rational &r) const +bool rational::operator>=(const rational &rhs) const { - return (numerator_ != r.numerator_) || (denominator_ != r.denominator_); + if(numer * denom == intType(0) && rhs.numer * rhs.denom == intType(0)) + return true; + else + if(numer * denom != intType(0) && rhs.numer * rhs.denom == intType(0)) + { + if(numer * denom > intType(0)) + return true; + else + return false; + } + else + if(numer * denom == intType(0) && rhs.numer * rhs.denom != intType(0)) + { + if(rhs.numer * rhs.denom > intType(0)) + return false; + else + return true; + } + else + + return ((numer * rhs.denom) >= (denom * rhs.numer)); } -const rational &rational::operator++() +bool rational::operator==(const rational &rhs) const { - numerator_ += denominator_; + return (numer == rhs.numer && denom == rhs.denom); +} + +bool rational::operator!=(const rational &rhs) const +{ + return (numer != rhs.numer) || (denom != rhs.denom); + +} + +//Unary operators + +const rational& rational::operator++() +{ + numer += denom; return *this; } rational rational::operator++(int) { rational tmp = *this; - numerator_ += denominator_; + numer += denom; return tmp; } -const rational &rational::operator--() +const rational& rational::operator--() { - numerator_ -= denominator_; + numer -= denom; return *this; + } rational rational::operator--(int) { rational tmp; - numerator_ -= denominator_; + numer -= denom; return tmp; } -const rational &rational::operator+() const +const rational& rational::operator+() const { return *this; } rational rational::operator-() const { - return rational(numerator_, -denominator_); + return rational(numer, -denom); } bool rational::operator!() const { - return !numerator_; + return !numer; } -double rational::ToDouble() const +//IO + +ostream& operator<<(ostream &out, const rational &value) { - if (denominator_ == 0) { - return 0; - } else { - return static_cast(numerator_)/static_cast(denominator_); - } -} - -const int64_t &rational::numerator() const -{ - return numerator_; -} - -const int64_t &rational::denominator() const -{ - return denominator_; -} - -rational rational::flipped() const -{ - return rational(denominator_, numerator_); -} - -void rational::FixSigns() -{ - // Ensures denominator is always positive (while numerator can be positive or negative) - if(denominator_ < 0) { - denominator_ = -denominator_; - numerator_ = -numerator_; - } - - // Ensures if either are zero, they're both zero - if(numerator_ == 0 || denominator_ == 0) { - numerator_ = 0; - denominator_ = 0; - } -} - -void rational::Reduce() -{ - int64_t d = 1; - - if(denominator_ != 0 && numerator_ != 0) { - d = GreatestCommonDenominator(numerator_, denominator_); - } - - if(d > 1) { - numerator_ /= d; - denominator_ /= d; - } -} - -int64_t rational::GreatestCommonDenominator(const int64_t& x, const int64_t& y) -{ - if (y == 0) { - return x; - } else { - int64_t tmp = x % y; - return GreatestCommonDenominator(y, tmp); - } -} - -std::ostream &operator<<(std::ostream &out, const rational &value) -{ - out << value.numerator_; - if(value.denominator_ != 1) - { - out << '/' << value.denominator_; - return out; - } + out << value.numer; + if(value.denom != 1) + { + out << '/' << value.denom; + return out; + } return out; } -std::istream &operator>>(std::istream &in, rational &value) +istream& operator>>(istream &in, rational &value) { - in >> value.numerator_; - value.denominator_ = 1; + in >> value.numer; + value.denom = 1; char ch; in.get(ch); if(!in.eof()) - { - if(ch == '/') { - in >> value.denominator_; - value.FixSigns(); - value.Reduce(); + if(ch == '/') + { + in >> value.denom; + value.fixSigns(); + value.reduce(); + } + else + in.putback(ch); } - else - in.putback(ch); - } return in; } + diff --git a/app/common/rational.h b/app/common/rational.h index 6ec18dd99..22298b108 100644 --- a/app/common/rational.h +++ b/app/common/rational.h @@ -1,72 +1,87 @@ -/*** +//Copyright 2015 Adam Quintero +//This program is distributed under the terms of the GNU General Public License. - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ +// Adapted by MattKC for the Olive Video Editor (2019) #ifndef RATIONAL_H #define RATIONAL_H - -// Adapted from https://github.com/angularadam/Qt-Class-rational used in compliance with the GNU General Public License - #include -/** - * Including AVFormat to support converting from AVRational to Olive's rational class - */ extern "C" { - #include +#include } -/** - * @brief A rational (numerator/denominator) class with C++ operations built in for ease of use. - * - * Rationals in Olive most frequently represent timing information to easily handle timing in various different - * frame/sample rates without the inaccuracy/rounding errors of a floating point type. - */ -class rational { +using namespace std; + +typedef long intType; +/* + * Zero Handling + * 0/0 = 0 + * 0/non-zero = 0 + * non-zero/0 = 0 +*/ +class rational +{ public: - // Constructors - rational(const int64_t& numerator = 0); - rational(const int64_t& numerator, const int64_t& denominator); - rational(const AVRational& r); // Auto-convert from an FFmpeg AVRational - rational(const rational& r); + //constructors + rational(const intType &numerator = 0) + :numer(numerator), denom(1) + { + activeInstances++; + if(numer == 0) + denom = 0; + } + + rational(const intType &numerator, const intType &denominator) + :numer(numerator), denom(denominator) + { + activeInstances++; + if(denom != intType(0)) + { + if(numer != intType(0)) + { + fixSigns(); + reduce(); + } + else + denom = intType(0); + } + else + numer = intType(0); + } + + rational(const rational &rhs) + :numer(rhs.numer), denom(rhs.denom) + { + activeInstances++; + } - // Assignment Operators - const rational& operator=(const rational& r); - const rational& operator+=(const rational& r); - const rational& operator-=(const rational& r); - const rational& operator/=(const rational& r); - const rational& operator*=(const rational& r); - - // Math Operators - rational operator+(const rational& r) const; - rational operator-(const rational& r) const; - rational operator/(const rational& r) const; - rational operator*(const rational& r) const; - - // Relational and Equality Operators - bool operator<(const rational &r) const; - bool operator<=(const rational &r) const; - bool operator>(const rational &r) const; - bool operator>=(const rational &r) const; - bool operator==(const rational &r) const; - bool operator!=(const rational &r) const; + rational(const AVRational& r); + + //destructor + ~rational(); + + //Assignment Operators + const rational& operator=(const rational &rhs); + const rational& operator+=(const rational &rhs); + const rational& operator-=(const rational &rhs); + const rational& operator/=(const rational &rhs); + const rational& operator*=(const rational &rhs); + //Binary math operators + rational operator+(const rational &rhs) const; + rational operator-(const rational &rhs) const; + rational operator/(const rational &rhs) const; + rational operator*(const rational &rhs) const; + + //Relational and equality operators + bool operator<(const rational &rhs) const; + bool operator<=(const rational &rhs) const; + bool operator>(const rational &rhs) const; + bool operator>=(const rational &rhs) const; + bool operator==(const rational &rhs) const; + bool operator!=(const rational &rhs) const; + //Unary operators const rational& operator++(); //prefix rational operator++(int); //postfix @@ -76,25 +91,39 @@ public: rational operator-() const; bool operator!() const; - // IO - friend std::ostream& operator<<(std::ostream &out, const rational& value); - friend std::istream& operator>>(std::istream &in, rational& value); - - // Convert to double - double ToDouble() const; - - // Specific values - const int64_t& numerator() const; - const int64_t& denominator() const; + //Function: convert to double + double toDouble() const; + // Produce "flipped" version rational flipped() const; -private: - int64_t numerator_; - int64_t denominator_; + + //Function: print number to cout + void print(ostream &out = cout) const; - void FixSigns(); - void Reduce(); - int64_t GreatestCommonDenominator(const int64_t &x, const int64_t &y); + //Function: get active instances + int getActiveInstances(); + + //IO + friend ostream& operator<<(ostream &out, const rational &value); + friend istream& operator>>(istream &in, rational &value); + + const intType& numerator() const; + const intType& denominator() const; + +private: + //number of active instances + static int activeInstances; + + //numerator and denominator + intType numer; + intType denom; + + //Function: ensures denom >= 0 + void fixSigns(); + //Function: ensures lowest form + void reduce(); + //Function: finds greatest common denominator + intType gcd(intType &x, intType &y); }; #endif // RATIONAL_H