rational: implement NaN mode

Also clarify code where 0 is used as a rational.
This commit is contained in:
itsmattkc
2021-04-17 15:04:03 +10:00
parent 88ebfb9d8e
commit 22b2d08baf
13 changed files with 132 additions and 108 deletions
+90 -72
View File
@@ -7,24 +7,28 @@ namespace olive {
rational rational::fromDouble(const double &flt, bool* ok)
{
if (qIsNaN(flt)) {
// Return NaN rational
if (ok) *ok = false;
return rational(0, 0);
}
// Use FFmpeg function for the time being
AVRational r = av_d2q(flt, INT_MAX);
if (r.den == 0) {
// If den == 0, we were unable to convert to a rational
if (ok) {
*ok = false;
}
return rational();
} else {
// Otherwise, assume we received a real rational
if (ok) {
*ok = true;
}
return r;
}
return r;
}
rational rational::fromString(const QString &str, bool* ok)
@@ -37,32 +41,32 @@ rational rational::fromString(const QString &str, bool* ok)
case 2:
return rational(elements.at(0).toLongLong(ok), elements.at(1).toLongLong(ok));
default:
// Returns NaN with ok set to false
if (ok) {
*ok = false;
}
return rational();
return rational(0, 0);
}
}
//Function: print number to cout
void rational::print(std::ostream &out) const
{
out << this->numer_ << "/" << this->denom_;
}
//Function: ensures denom >= 0
void rational::fix_signs()
{
// Normalize so that denominator is always positive and only numerator is positive
if (denom_ < 0) {
denom_ = -denom_;
numer_ = -numer_;
}
if (numer_ == intType(0) || denom_ == intType(0)) {
// Normalize to 0/1 if numerator is zero
if (numer_ == intType(0)) {
denom_ = intType(1);
}
// Normalize to 0/0 (aka NaN) if denominator is zero
if (denom_ == intType(0)) {
numer_ = intType(0);
denom_ = intType(0);
}
}
@@ -107,7 +111,7 @@ double rational::toDouble() const
if (denom_ != 0) {
return static_cast<double>(numer_) / static_cast<double>(denom_);
} else {
return static_cast<double>(0);
return qSNaN();
}
}
@@ -137,6 +141,11 @@ rational rational::flipped() const
}
bool rational::isNull() const
{
return numerator() == 0;
}
bool rational::isNaN() const
{
return denominator() == 0;
}
@@ -170,15 +179,21 @@ const rational& rational::operator=(const rational &rhs)
const rational& rational::operator+=(const rational &rhs)
{
if (!rhs.isNull()) {
if (isNull()) {
numer_ = rhs.numer_;
denom_ = rhs.denom_;
} else {
numer_ = (numer_ * rhs.denom_) + (rhs.numer_ * denom_);
denom_ = denom_ * rhs.denom_;
if (!isNaN()) {
if (rhs.isNaN()) {
// Set to NaN
denom_ = 0;
fix_signs();
reduce();
} else if (!rhs.isNull()) {
if (isNull()) {
numer_ = rhs.numer_;
denom_ = rhs.denom_;
} else {
numer_ = (numer_ * rhs.denom_) + (rhs.numer_ * denom_);
denom_ = denom_ * rhs.denom_;
fix_signs();
reduce();
}
}
}
@@ -187,15 +202,21 @@ const rational& rational::operator+=(const rational &rhs)
const rational& rational::operator-=(const rational &rhs)
{
if (!rhs.isNull()) {
if (isNull()) {
numer_ = -rhs.numer_;
denom_ = rhs.denom_;
} else {
numer_ = (numer_ * rhs.denom_) - (rhs.numer_ * denom_);
denom_ = denom_ * rhs.denom_;
if (!isNaN()) {
if (rhs.isNaN()) {
// Set to NaN
denom_ = 0;
fix_signs();
reduce();
} else if (!rhs.isNull()) {
if (isNull()) {
numer_ = -rhs.numer_;
denom_ = rhs.denom_;
} else {
numer_ = (numer_ * rhs.denom_) - (rhs.numer_ * denom_);
denom_ = denom_ * rhs.denom_;
fix_signs();
reduce();
}
}
}
@@ -204,19 +225,36 @@ const rational& rational::operator-=(const rational &rhs)
const rational& rational::operator/=(const rational &rhs)
{
numer_ = numer_ * rhs.denom_;
denom_ = denom_ * rhs.numer_;
fix_signs();
reduce();
if (!isNaN()) {
if (rhs.isNaN()) {
// Set to NaN
denom_ = 0;
fix_signs();
} else {
numer_ = numer_ * rhs.denom_;
denom_ = denom_ * rhs.numer_;
fix_signs();
reduce();
}
}
return *this;
}
const rational& rational::operator*=(const rational &rhs)
{
numer_ = numer_ * rhs.numer_;
denom_ = denom_ * rhs.denom_;
fix_signs();
reduce();
if (!isNaN()) {
if (rhs.isNaN()) {
denom_ = 0;
fix_signs();
} else {
numer_ = numer_ * rhs.numer_;
denom_ = denom_ * rhs.denom_;
fix_signs();
reduce();
}
}
return *this;
}
@@ -254,6 +292,10 @@ rational rational::operator*(const rational &rhs) const
bool rational::operator<(const rational &rhs) const
{
if (isNaN() || rhs.isNaN()) {
return false;
}
if (isNull() && rhs.isNull()) {
return false;
}
@@ -283,6 +325,10 @@ bool rational::operator<(const rational &rhs) const
bool rational::operator<=(const rational &rhs) const
{
if (isNaN() || rhs.isNaN()) {
return false;
}
if (isNull() && rhs.isNull()) {
return true;
}
@@ -322,40 +368,16 @@ bool rational::operator>=(const rational &rhs) const
bool rational::operator==(const rational &rhs) const
{
if (isNaN() || rhs.isNaN()) {
return false;
}
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;
numer_ += denom_;
return tmp;
}
const rational& rational::operator--()
{
numer_ -= denom_;
return *this;
}
rational rational::operator--(int)
{
rational tmp;
numer_ -= denom_;
return tmp;
return !(*this == rhs);
}
const rational& rational::operator+() const
@@ -417,8 +439,4 @@ uint qHash(const rational &r, uint seed)
QDebug operator<<(QDebug debug, const olive::rational &r)
{
return debug.space() << r.toDouble();
/*
debug.nospace() << r.numerator() << "/" << r.denominator();
return debug.space();
*/
}