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-12-21 08:56:24 Functions: 24 49 49.0 %

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

Generated by: LCOV version 1.14