rational: implement NaN mode
Also clarify code where 0 is used as a rational.
This commit is contained in:
+90
-72
@@ -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();
|
||||
*/
|
||||
}
|
||||
|
||||
+7
-13
@@ -34,13 +34,9 @@ class rational
|
||||
public:
|
||||
//constructors
|
||||
rational(const intType &numerator = 0) :
|
||||
numer_(numerator)
|
||||
numer_(numerator),
|
||||
denom_(1)
|
||||
{
|
||||
if (numer_ == 0) {
|
||||
denom_ = 0;
|
||||
} else {
|
||||
denom_ = 1;
|
||||
}
|
||||
}
|
||||
|
||||
rational(const intType &numerator, const intType &denominator) :
|
||||
@@ -87,10 +83,6 @@ public:
|
||||
bool operator!=(const rational &rhs) const;
|
||||
|
||||
//Unary operators
|
||||
const rational& operator++(); //prefix
|
||||
rational operator++(int); //postfix
|
||||
const rational& operator--(); //prefix
|
||||
rational operator--(int); //postfix
|
||||
const rational& operator+() const;
|
||||
rational operator-() const;
|
||||
bool operator!() const;
|
||||
@@ -108,11 +100,13 @@ public:
|
||||
// Produce "flipped" version
|
||||
rational flipped() const;
|
||||
|
||||
// Returns whether the rational is null or not
|
||||
// Returns whether the rational is valid but equal to zero or not
|
||||
//
|
||||
// A NaN is always a null, but a null is not always a NaN
|
||||
bool isNull() const;
|
||||
|
||||
//Function: print number to cout
|
||||
void print(std::ostream &out = std::cout) const;
|
||||
// Returns whether this rational is not a valid number
|
||||
bool isNaN() const;
|
||||
|
||||
//IO
|
||||
friend std::ostream& operator<<(std::ostream &out, const rational &value);
|
||||
|
||||
Reference in New Issue
Block a user