Skip to content
Snippets Groups Projects
Select Git revision
  • master default protected
  • release/202005
  • release/202001
  • release/201912
  • release/201911
  • release/releaseWindowsTestOne
  • release/windowsReleaseTest
  • release/releaseTest
  • release/releaseWindowsTest
  • release/201910
  • release/qt/201910
  • release/windows-test/201910
  • release/201908
  • release/201906
  • release/201905
  • release/201904
  • release/201903
  • release/201902
  • release/201901
  • release/201812
  • 4.0.0
  • 2.2.0
  • 2.1.0
  • 2.0.1
  • 2.0.0
  • 1.4.1
  • 1.4.0
  • 1.3.0
  • 1.2.0
  • 1.1.0
30 results

rational.h

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    rational.h 6.88 KiB
    /*
     *  Copyright (C) 2004-2024 Savoir-faire Linux Inc.
     *
     *  Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
     *
     *  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 <utility> // std::swap
    #include <cstdlib> // std::abs
    #include <iostream>
    #include <cmath>      // std::fmod
    #include <functional> // std::modulus
    #include <ciso646>    // and, or ...
    
    extern "C" {
    #include <libavutil/rational.h> // specify conversions for AVRational
    }
    
    namespace jami {
    
    /**
     * Naive implementation of the boost::rational interface, described here:
     * http://www.boost.org/doc/libs/1_57_0/libs/rational/rational.html
     */
    template<typename I>
    class rational
    {
    public:
        // Constructors
        constexpr rational() {} // Zero
        constexpr rational(I n)
            : num_(n) {} // Equal to n/1
        constexpr rational(I n, I d)
            : num_(n)
            , den_(d)
        {
            reduce();
        } // General case (n/d)
    
        // Define conversions to and from AVRational (equivalent)
        constexpr rational(AVRational r)
            : num_(r.num)
            , den_(r.den) {};
        constexpr operator AVRational() const { return AVRational {(int) num_, (int) 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;
            reduce();
            return *this;
        }
    
        // Representation
        constexpr I numerator() const { return num_; };
        constexpr I denominator() const { return den_; };
    
        template<typename R = double>
        constexpr 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
        constexpr rational operator+(const rational& r) const
        {
            return {num_ * r.den_ + r.num_ * den_, den_ * r.den_};
        }
        constexpr rational operator-(const rational& r) const
        {
            return {num_ * r.den_ - r.num_ * den_, den_ * r.den_};
        }
        constexpr rational operator*(const rational& r) const { return {num_ * r.num_, den_ * r.den_}; }
        constexpr rational operator/(const rational& r) const { 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_;
            reduce();
            return *this;
        }
        rational& operator/=(const rational& r)
        {
            num_ *= r.den_;
            den_ *= r.num_;
            reduce();
            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;
            reduce();
            return *this;
        }
        rational& operator/=(I i)
        {
            den_ *= i;
            reduce();
            return *this;
        }
    
        // Increment and decrement
        const rational& operator++()
        {
            num_ += den_;
            return *this;
        }
        const rational& operator--()
        {
            num_ -= den_;
            return *this;
        }
    
        // Operator not
        constexpr bool operator!() const { return !num_; };
    
        // Boolean conversion
        explicit constexpr operator bool() const { return num_; }
    
        // Comparison operators
        constexpr bool operator<(const rational& r) const
        {
            bool inv = (den_ > 0) != (r.den_ > 0);
            return inv != (num_ * r.den_ < den_ * r.num_);
        }
        constexpr bool operator>(const rational& r) const
        {
            bool inv = (den_ > 0) != (r.den_ > 0);
            return inv != (num_ * r.den_ > den_ * r.num_);
        }
        constexpr bool operator==(const rational& r) const { return num_ * r.den_ == den_ * r.num_; }
        constexpr bool operator!=(const rational& r) const { return num_ * r.den_ != den_ * r.num_; }
    
        // Comparison with integers
        constexpr bool operator<(I i) const { return den_ < 0 ? (num_ > i * den_) : (num_ < i * den_); }
        constexpr bool operator>(I i) const { return den_ < 0 ? (num_ < i * den_) : (num_ > i * den_); }
        constexpr bool operator==(I i) const { return num_ == i * den_; }
        constexpr bool operator!=(I i) const { return num_ != i * den_; }
    
    private:
        I num_ {0};
        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
    template<typename I>
    rational<I>
    operator+(const rational<I>& r)
    {
        return r;
    }
    template<typename I>
    rational<I>
    operator-(const rational<I>& r)
    {
        return {-r.numerator(), r.denominator()};
    };
    
    // Reversed order operators for - and / between (types convertible to) I and rational
    template<typename I, typename II>
    inline rational<I> operator-(II i, const rational<I>& r);
    template<typename I, typename II>
    inline rational<I>
    operator/(II i, const rational<I>& r)
    {
        return {i * r.denominator(), r.numerator()};
    }
    
    // Absolute value
    template<typename I>
    rational<I>
    abs(const rational<I>& r)
    {
        return {std::abs(r.numerator()), std::abs(r.denominator())};
    }
    
    // Input and output
    template<typename I>
    std::istream&
    operator>>(std::istream& is, rational<I>& r)
    {
        char sep;
        is >> r.num_ >> sep >> r.den_;
        return is;
    }
    
    template<typename I>
    std::ostream&
    operator<<(std::ostream& os, const rational<I>& r)
    {
        os << r.numerator() << '/' << r.denominator();
        return os;
    }
    
    // Type conversion
    template<typename T, typename I>
    T rational_cast(const rational<I>& r);
    
    } // namespace jami
    
    namespace std {
    template<>
    struct modulus<double>
    {
        double operator()(const double& lhs, const double& rhs) const { return std::fmod(lhs, rhs); }
    };
    } // namespace std