Skip to content
Snippets Groups Projects
Commit 2dbaf0fd authored by Adrien Béraud's avatar Adrien Béraud Committed by Philippe Gorley
Browse files

rational: add auto-simplification


Change-Id: I506dca0e5c4bb58b0c639219d4a4224f85fb2611
Reviewed-by: default avatarPhilippe Gorley <philippe.gorley@savoirfairelinux.com>
parent 70a1080f
Branches
No related tags found
No related merge requests found
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include "config.h" #include "config.h"
#include "rational.h"
#ifdef RING_VIDEO #ifdef RING_VIDEO
#include "video/video_base.h" #include "video/video_base.h"
#include "video/video_scaler.h" #include "video/video_scaler.h"
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <utility> // std::swap #include <utility> // std::swap
#include <cstdlib> // std::abs #include <cstdlib> // std::abs
#include <iostream> #include <iostream>
#include <cmath> // std::fmod
extern "C" { extern "C" {
#include <libavutil/rational.h> // specify conversions for AVRational #include <libavutil/rational.h> // specify conversions for AVRational
...@@ -33,7 +34,6 @@ namespace ring { ...@@ -33,7 +34,6 @@ namespace ring {
/** /**
* Naive implementation of the boost::rational interface, described here: * Naive implementation of the boost::rational interface, described here:
* http://www.boost.org/doc/libs/1_57_0/libs/rational/rational.html * http://www.boost.org/doc/libs/1_57_0/libs/rational/rational.html
* No form of normalisation or overflow prevention is implemented.
*/ */
template<typename I> template<typename I>
class rational { class rational {
...@@ -41,7 +41,9 @@ public: ...@@ -41,7 +41,9 @@ public:
// Constructors // Constructors
rational() {}; // Zero rational() {}; // Zero
rational(I n) : num_(n) {}; // Equal to n/1 rational(I n) : num_(n) {}; // Equal to n/1
rational(I n, I d) : num_(n), den_(d) {}; // General case (n/d) rational(I n, I d) : num_(n), den_(d) {
reduce();
}; // General case (n/d)
// Define conversions to and from AVRational (equivalent) // Define conversions to and from AVRational (equivalent)
rational(AVRational r) : num_(r.num), den_(r.den) {}; rational(AVRational r) : num_(r.num), den_(r.den) {};
...@@ -53,7 +55,7 @@ public: ...@@ -53,7 +55,7 @@ public:
rational& operator=(I n) { num_ = n; den_ = 1; return *this; } rational& operator=(I n) { num_ = n; den_ = 1; return *this; }
// Assign in place // Assign in place
rational& assign(I n, I d) { num_ = n; den_ = d; return *this; } rational& assign(I n, I d) { num_ = n; den_ = d; reduce(); return *this; }
// Representation // Representation
I numerator() const { return num_; }; I numerator() const { return num_; };
...@@ -88,19 +90,21 @@ public: ...@@ -88,19 +90,21 @@ public:
rational& operator*= (const rational& r) { rational& operator*= (const rational& r) {
num_ *= r.num_; num_ *= r.num_;
den_ *= r.den_; den_ *= r.den_;
reduce();
return *this; return *this;
} }
rational& operator/= (const rational& r) { rational& operator/= (const rational& r) {
num_ *= r.den_; num_ *= r.den_;
den_ *= r.num_; den_ *= r.num_;
reduce();
return *this; return *this;
} }
// Arithmetic with integers // Arithmetic with integers
rational& operator+= (I i) { num_ += i * den_; return *this; } rational& operator+= (I i) { num_ += i * den_; return *this; }
rational& operator-= (I i) { num_ -= i * den_; return *this; } rational& operator-= (I i) { num_ -= i * den_; return *this; }
rational& operator*= (I i) { num_ *= i; return *this; } rational& operator*= (I i) { num_ *= i; reduce(); return *this; }
rational& operator/= (I i) { den_ *= i; return *this; }; rational& operator/= (I i) { den_ *= i; reduce(); return *this; }
// Increment and decrement // Increment and decrement
const rational& operator++() { num_ += den_; return *this; } const rational& operator++() { num_ += den_; return *this; }
...@@ -132,6 +136,21 @@ public: ...@@ -132,6 +136,21 @@ public:
private: private:
I num_ {0}; I num_ {0};
I den_ {1}; I den_ {1};
static constexpr I gcd ( I a, I b ) {
return b == (I)0 ? a : gcd(b, std::modulus<I>()(a, b));
}
void reduce() {
if (std::is_integral<I>::value) {
if (num_ and den_) {
auto g = gcd(num_ >= 0 ? num_ : -num_, den_ >= 0 ? den_ : -den_);
if (g > (I)1) {
num_ /= g;
den_ /= g;
}
}
}
}
}; };
// Unary operators // Unary operators
...@@ -165,3 +184,12 @@ template <typename I> std::ostream& operator<< (std::ostream& os, const rational ...@@ -165,3 +184,12 @@ template <typename I> std::ostream& operator<< (std::ostream& os, const rational
template <typename T, typename I> T rational_cast (const rational<I>& r); template <typename T, typename I> T rational_cast (const rational<I>& r);
} }
namespace std {
template <>
struct modulus<double> {
double operator()(const double &lhs, const double &rhs) const {
return std::fmod(lhs, rhs);
}
};
} // namespace std
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment