/* * Copyright (C) 2015-2018 Savoir-faire Linux Inc. * * Author: Adrien Béraud * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once #include // std::swap #include // std::abs #include extern "C" { #include // specify conversions for AVRational } namespace ring { /** * Naive implementation of the boost::rational interface, described here: * http://www.boost.org/doc/libs/1_57_0/libs/rational/rational.html * No form of normalisation or overflow prevention is implemented. */ template class rational { public: // Constructors rational() {}; // Zero rational(I n) : num_(n) {}; // Equal to n/1 rational(I n, I d) : num_(n), den_(d) {}; // General case (n/d) // Define conversions to and from AVRational (equivalent) rational(AVRational r) : num_(r.num), den_(r.den) {}; operator AVRational() { return AVRational{num_, den_}; } // Normal copy constructors and assignment operators // Assignment from I rational& operator=(I n) { num_ = n; den_ = 1; return *this; } // Assign in place rational& assign(I n, I d) { num_ = n; den_ = d; return *this; } // Representation I numerator() const { return num_; }; I denominator() const { return den_; }; template R real() const { return num_/(R)den_; } // In addition to the following operators, all of the "obvious" derived // operators are available - see operators.hpp // Arithmetic operators rational operator+ (const rational& r) { return {num_*r.den_ + r.num_*den_, den_*r.den_}; } rational operator- (const rational& r) { return {num_*r.den_ - r.num_*den_, den_*r.den_}; } rational operator* (const rational& r) { return {num_*r.num_, den_*r.den_}; } rational operator/ (const rational& r) { return {num_*r.den_, den_*r.num_}; } rational& operator+= (const rational& r) { std::swap(*this, *this + r); return *this; } rational& operator-= (const rational& r) { std::swap(*this, *this - r); return *this; } rational& operator*= (const rational& r) { num_ *= r.num_; den_ *= r.den_; return *this; } rational& operator/= (const rational& r) { num_ *= r.den_; den_ *= r.num_; return *this; } // 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; return *this; } rational& operator/= (I i) { den_ *= i; return *this; }; // Increment and decrement const rational& operator++() { num_ += den_; return *this; } const rational& operator--() { num_ -= den_; return *this; } // Operator not bool operator!() const { return !num_; }; // Boolean conversion explicit operator bool() const { return num_; } // Comparison operators bool operator< (const rational& r) const { bool inv = (den_ > 0) != (r.den_ > 0); return inv != (num_ * r.den_ < den_ * r.num_); } bool operator== (const rational& r) const { return num_ * r.den_ == den_ * r.num_; } // Comparison with integers bool operator< (I i) const { return num_ < i * den_; } bool operator> (I i) const { return num_ > i * den_; } bool operator== (I i) const { return num_ == i * den_; } private: I num_ {0}; I den_ {1}; }; // Unary operators template rational operator+ (const rational& r) { return r; } template rational operator- (const rational& r) { return {-r.numerator(), r.denominator()}; }; // Reversed order operators for - and / between (types convertible to) I and rational template inline rational operator- (II i, const rational& r); template inline rational operator/ (II i, const rational& r) { return { i * r.denominator(), r.numerator() }; } // Absolute value template rational abs (const rational& r) { return { std::abs(r.numerator()), std::abs(r.denominator()) }; } // Input and output template std::istream& operator>> (std::istream& is, rational& r) { char sep; is >> r.num_ >> sep >> r.den_; return is; } template std::ostream& operator<< (std::ostream& os, const rational& r) { os << r.numerator() << '/' << r.denominator(); return os; } // Type conversion template T rational_cast (const rational& r); }