LCOV - code coverage report
Current view: top level - src - rational.h (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 34 43 79.1 %
Date: 2024-04-25 08:05:53 Functions: 24 51 47.1 %

          Line data    Source code
       1             : /*
       2             :  *  Copyright (C) 2004-2024 Savoir-faire Linux Inc.
       3             :  *
       4             :  *  Author: Adrien BĂ©raud <adrien.beraud@savoirfairelinux.com>
       5             :  *
       6             :  *  This program is free software; you can redistribute it and/or modify
       7             :  *  it under the terms of the GNU General Public License as published by
       8             :  *  the Free Software Foundation; either version 3 of the License, or
       9             :  *  (at your option) any later version.
      10             :  *
      11             :  *  This program is distributed in the hope that it will be useful,
      12             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  *  GNU General Public License for more details.
      15             :  *
      16             :  *  You should have received a copy of the GNU General Public License
      17             :  *  along with this program; if not, write to the Free Software
      18             :  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
      19             :  */
      20             : 
      21             : #pragma once
      22             : 
      23             : #include <utility> // std::swap
      24             : #include <cstdlib> // std::abs
      25             : #include <iostream>
      26             : #include <cmath>      // std::fmod
      27             : #include <functional> // std::modulus
      28             : #include <ciso646>    // and, or ...
      29             : 
      30             : extern "C" {
      31             : #include <libavutil/rational.h> // specify conversions for AVRational
      32             : }
      33             : 
      34             : namespace jami {
      35             : 
      36             : /**
      37             :  * Naive implementation of the boost::rational interface, described here:
      38             :  * http://www.boost.org/doc/libs/1_57_0/libs/rational/rational.html
      39             :  */
      40             : template<typename I>
      41             : class rational
      42             : {
      43             : public:
      44             :     // Constructors
      45        5629 :     constexpr rational() {} // Zero
      46           1 :     constexpr rational(I n)
      47           1 :         : num_(n) {} // Equal to n/1
      48         483 :     constexpr rational(I n, I d)
      49         483 :         : num_(n)
      50         483 :         , den_(d)
      51             :     {
      52         483 :         reduce();
      53         483 :     } // General case (n/d)
      54             : 
      55             :     // Define conversions to and from AVRational (equivalent)
      56         359 :     constexpr rational(AVRational r)
      57         359 :         : num_(r.num)
      58         359 :         , den_(r.den) {};
      59         334 :     constexpr operator AVRational() const { return AVRational {(int) num_, (int) den_}; }
      60             : 
      61             :     // Normal copy constructors and assignment operators
      62             : 
      63             :     // Assignment from I
      64         325 :     rational& operator=(I n)
      65             :     {
      66         325 :         num_ = n;
      67         325 :         den_ = 1;
      68         325 :         return *this;
      69             :     }
      70             : 
      71             :     // Assign in place
      72             :     rational& assign(I n, I d)
      73             :     {
      74             :         num_ = n;
      75             :         den_ = d;
      76             :         reduce();
      77             :         return *this;
      78             :     }
      79             : 
      80             :     // Representation
      81         314 :     constexpr I numerator() const { return num_; };
      82         160 :     constexpr I denominator() const { return den_; };
      83             : 
      84             :     template<typename R = double>
      85        1095 :     constexpr R real() const
      86             :     {
      87        1095 :         return num_ / (R) den_;
      88             :     }
      89             : 
      90             :     // In addition to the following operators, all of the "obvious" derived
      91             :     // operators are available - see operators.hpp
      92             : 
      93             :     // Arithmetic operators
      94             :     constexpr rational operator+(const rational& r) const
      95             :     {
      96             :         return {num_ * r.den_ + r.num_ * den_, den_ * r.den_};
      97             :     }
      98           0 :     constexpr rational operator-(const rational& r) const
      99             :     {
     100           0 :         return {num_ * r.den_ - r.num_ * den_, den_ * r.den_};
     101             :     }
     102           0 :     constexpr rational operator*(const rational& r) const { return {num_ * r.num_, den_ * r.den_}; }
     103             :     constexpr rational operator/(const rational& r) const { return {num_ * r.den_, den_ * r.num_}; }
     104             : 
     105             :     rational& operator+=(const rational& r)
     106             :     {
     107             :         std::swap(*this, *this + r);
     108             :         return *this;
     109             :     }
     110             :     rational& operator-=(const rational& r)
     111             :     {
     112             :         std::swap(*this, *this - r);
     113             :         return *this;
     114             :     }
     115             :     rational& operator*=(const rational& r)
     116             :     {
     117             :         num_ *= r.num_;
     118             :         den_ *= r.den_;
     119             :         reduce();
     120             :         return *this;
     121             :     }
     122             :     rational& operator/=(const rational& r)
     123             :     {
     124             :         num_ *= r.den_;
     125             :         den_ *= r.num_;
     126             :         reduce();
     127             :         return *this;
     128             :     }
     129             : 
     130             :     // Arithmetic with integers
     131             :     rational& operator+=(I i)
     132             :     {
     133             :         num_ += i * den_;
     134             :         return *this;
     135             :     }
     136             :     rational& operator-=(I i)
     137             :     {
     138             :         num_ -= i * den_;
     139             :         return *this;
     140             :     }
     141             :     rational& operator*=(I i)
     142             :     {
     143             :         num_ *= i;
     144             :         reduce();
     145             :         return *this;
     146             :     }
     147             :     rational& operator/=(I i)
     148             :     {
     149             :         den_ *= i;
     150             :         reduce();
     151             :         return *this;
     152             :     }
     153             : 
     154             :     // Increment and decrement
     155             :     const rational& operator++()
     156             :     {
     157             :         num_ += den_;
     158             :         return *this;
     159             :     }
     160             :     const rational& operator--()
     161             :     {
     162             :         num_ -= den_;
     163             :         return *this;
     164             :     }
     165             : 
     166             :     // Operator not
     167         161 :     constexpr bool operator!() const { return !num_; };
     168             : 
     169             :     // Boolean conversion
     170         402 :     explicit constexpr operator bool() const { return num_; }
     171             : 
     172             :     // Comparison operators
     173         304 :     constexpr bool operator<(const rational& r) const
     174             :     {
     175         304 :         bool inv = (den_ > 0) != (r.den_ > 0);
     176         304 :         return inv != (num_ * r.den_ < den_ * r.num_);
     177             :     }
     178             :     constexpr bool operator>(const rational& r) const
     179             :     {
     180             :         bool inv = (den_ > 0) != (r.den_ > 0);
     181             :         return inv != (num_ * r.den_ > den_ * r.num_);
     182             :     }
     183           0 :     constexpr bool operator==(const rational& r) const { return num_ * r.den_ == den_ * r.num_; }
     184             :     constexpr bool operator!=(const rational& r) const { return num_ * r.den_ != den_ * r.num_; }
     185             : 
     186             :     // Comparison with integers
     187          38 :     constexpr bool operator<(I i) const { return den_ < 0 ? (num_ > i * den_) : (num_ < i * den_); }
     188             :     constexpr bool operator>(I i) const { return den_ < 0 ? (num_ < i * den_) : (num_ > i * den_); }
     189             :     constexpr bool operator==(I i) const { return num_ == i * den_; }
     190             :     constexpr bool operator!=(I i) const { return num_ != i * den_; }
     191             : 
     192             : private:
     193             :     I num_ {0};
     194             :     I den_ {1};
     195             : 
     196         916 :     static constexpr I gcd(I a, I b) { return b == (I) 0 ? a : gcd(b, std::modulus<I>()(a, b)); }
     197         483 :     void reduce()
     198             :     {
     199             :         if (std::is_integral<I>::value) {
     200         435 :             if (num_ and den_) {
     201         324 :                 auto g = gcd(num_ >= 0 ? num_ : -num_, den_ >= 0 ? den_ : -den_);
     202         324 :                 if (g > (I) 1) {
     203           0 :                     num_ /= g;
     204           0 :                     den_ /= g;
     205             :                 }
     206             :             }
     207             :         }
     208         483 :     }
     209             : };
     210             : 
     211             : // Unary operators
     212             : template<typename I>
     213             : rational<I>
     214             : operator+(const rational<I>& r)
     215             : {
     216             :     return r;
     217             : }
     218             : template<typename I>
     219             : rational<I>
     220             : operator-(const rational<I>& r)
     221             : {
     222             :     return {-r.numerator(), r.denominator()};
     223             : };
     224             : 
     225             : // Reversed order operators for - and / between (types convertible to) I and rational
     226             : template<typename I, typename II>
     227             : inline rational<I> operator-(II i, const rational<I>& r);
     228             : template<typename I, typename II>
     229             : inline rational<I>
     230         108 : operator/(II i, const rational<I>& r)
     231             : {
     232         108 :     return {i * r.denominator(), r.numerator()};
     233             : }
     234             : 
     235             : // Absolute value
     236             : template<typename I>
     237             : rational<I>
     238             : abs(const rational<I>& r)
     239             : {
     240             :     return {std::abs(r.numerator()), std::abs(r.denominator())};
     241             : }
     242             : 
     243             : // Input and output
     244             : template<typename I>
     245             : std::istream&
     246             : operator>>(std::istream& is, rational<I>& r)
     247             : {
     248             :     char sep;
     249             :     is >> r.num_ >> sep >> r.den_;
     250             :     return is;
     251             : }
     252             : 
     253             : template<typename I>
     254             : std::ostream&
     255           0 : operator<<(std::ostream& os, const rational<I>& r)
     256             : {
     257           0 :     os << r.numerator() << '/' << r.denominator();
     258           0 :     return os;
     259             : }
     260             : 
     261             : // Type conversion
     262             : template<typename T, typename I>
     263             : T rational_cast(const rational<I>& r);
     264             : 
     265             : } // namespace jami
     266             : 
     267             : namespace std {
     268             : template<>
     269             : struct modulus<double>
     270             : {
     271             :     double operator()(const double& lhs, const double& rhs) const { return std::fmod(lhs, rhs); }
     272             : };
     273             : } // namespace std

Generated by: LCOV version 1.14