Ring Daemon
Loading...
Searching...
No Matches
rational.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2026 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
25#include <fmt/format.h>
26
27extern "C" {
28#include <libavutil/rational.h> // specify conversions for AVRational
29}
30
31namespace jami {
32
37template<typename I>
39{
40public:
41 // Zero
42 constexpr rational() {}
43
44 // Equal to n/1
45 constexpr rational(I n)
46 : num_(n)
47 {}
48
49 // General case (n/d)
50 constexpr rational(I n, I d)
51 : num_(n)
52 , den_(d)
53 {
54 reduce();
55 }
56
57 // Define conversions to and from AVRational (equivalent)
58 constexpr rational(AVRational r)
59 : num_(r.num)
60 , den_(r.den) {};
61 constexpr operator AVRational() const { return AVRational {(int) num_, (int) den_}; }
62
63 std::string to_string() const { return fmt::format("{}/{}", num_, den_); }
64
65 // Normal copy constructors and assignment operators
66
67 // Assignment from I
69 {
70 num_ = n;
71 den_ = 1;
72 return *this;
73 }
74
75 // Assign in place
77 {
78 num_ = n;
79 den_ = d;
80 reduce();
81 return *this;
82 }
83
84 // Representation
85 constexpr I numerator() const { return num_; };
86 constexpr I denominator() const { return den_; };
87
88 template<typename R = double>
89 constexpr R real() const
90 {
91 return num_ / (R) den_;
92 }
93
94 // Arithmetic operators
95 constexpr rational operator+(const rational& r) const { return {num_ * r.den_ + r.num_ * den_, den_ * r.den_}; }
96 constexpr rational operator-(const rational& r) const { return {num_ * r.den_ - r.num_ * den_, den_ * r.den_}; }
97 constexpr rational operator*(const rational& r) const { return {num_ * r.num_, den_ * r.den_}; }
98 constexpr rational operator/(const rational& r) const { return {num_ * r.den_, den_ * r.num_}; }
99
100 constexpr rational& operator+=(const rational& r)
101 {
102 std::swap(*this, *this + r);
103 return *this;
104 }
105 constexpr rational& operator-=(const rational& r)
106 {
107 std::swap(*this, *this - r);
108 return *this;
109 }
110 constexpr rational& operator*=(const rational& r)
111 {
112 num_ *= r.num_;
113 den_ *= r.den_;
114 reduce();
115 return *this;
116 }
117 constexpr rational& operator/=(const rational& r)
118 {
119 num_ *= r.den_;
120 den_ *= r.num_;
121 reduce();
122 return *this;
123 }
124
125 // Arithmetic with integers
126 constexpr rational& operator+=(I i)
127 {
128 num_ += i * den_;
129 return *this;
130 }
131 constexpr rational& operator-=(I i)
132 {
133 num_ -= i * den_;
134 return *this;
135 }
136 constexpr rational& operator*=(I i)
137 {
138 num_ *= i;
139 reduce();
140 return *this;
141 }
142 constexpr rational& operator/=(I i)
143 {
144 den_ *= i;
145 reduce();
146 return *this;
147 }
148
149 // Increment and decrement
150 constexpr const rational& operator++()
151 {
152 num_ += den_;
153 return *this;
154 }
155 constexpr const rational& operator--()
156 {
157 num_ -= den_;
158 return *this;
159 }
160
161 // Operator not
162 constexpr bool operator!() const { return !num_; };
163
164 // Boolean conversion
165 explicit constexpr operator bool() const { return num_; }
166
167 // Comparison operators
168 constexpr bool operator<(const rational& r) const
169 {
170 bool inv = (den_ > 0) != (r.den_ > 0);
171 return inv != (num_ * r.den_ < den_ * r.num_);
172 }
173 constexpr bool operator>(const rational& r) const
174 {
175 bool inv = (den_ > 0) != (r.den_ > 0);
176 return inv != (num_ * r.den_ > den_ * r.num_);
177 }
178 constexpr bool operator==(const rational& r) const { return num_ * r.den_ == den_ * r.num_; }
179 constexpr bool operator!=(const rational& r) const { return num_ * r.den_ != den_ * r.num_; }
180
181 // Comparison with integers
182 constexpr bool operator<(I i) const { return den_ < 0 ? (num_ > i * den_) : (num_ < i * den_); }
183 constexpr bool operator>(I i) const { return den_ < 0 ? (num_ < i * den_) : (num_ > i * den_); }
184 constexpr bool operator==(I i) const { return num_ == i * den_; }
185 constexpr bool operator!=(I i) const { return num_ != i * den_; }
186
187private:
188 I num_ {0};
189 I den_ {1};
190
191 static constexpr I gcd(I a, I b) { return b == (I) 0 ? a : gcd(b, std::modulus<I>()(a, b)); }
192 constexpr void reduce()
193 {
194 if constexpr (std::is_integral<I>::value) {
195 if (num_ and den_) {
196 auto g = gcd(num_ >= 0 ? num_ : -num_, den_ >= 0 ? den_ : -den_);
197 if (g > (I) 1) {
198 num_ /= g;
199 den_ /= g;
200 }
201 }
202 }
203 }
204};
205
206// Unary operators
207template<typename I>
210{
211 return r;
212}
213template<typename I>
216{
217 return {-r.numerator(), r.denominator()};
218}
219
220// Reversed order operators for - and / between (types convertible to) I and rational
221template<typename I, typename II>
223template<typename I, typename II>
224inline rational<I>
226{
227 return {i * r.denominator(), r.numerator()};
228}
229
230// Absolute value
231template<typename I>
234{
235 return {std::abs(r.numerator()), std::abs(r.denominator())};
236}
237
238// Input and output
239template<typename I>
240std::istream&
241operator>>(std::istream& is, rational<I>& r)
242{
243 char sep;
244 is >> r.num_ >> sep >> r.den_;
245 return is;
246}
247
248template<typename I>
249std::ostream&
250operator<<(std::ostream& os, const rational<I>& r)
251{
252 os << r.numerator() << '/' << r.denominator();
253 return os;
254}
255
256// Type conversion
257template<typename T, typename I>
259
260} // namespace jami
261
262namespace std {
263template<>
264struct modulus<double>
265{
266 double operator()(const double& lhs, const double& rhs) const { return std::fmod(lhs, rhs); }
267};
268} // namespace std
269
270template<typename I>
271struct fmt::formatter<jami::rational<I>> : fmt::formatter<std::string_view>
272{
273 template<typename FormatContext>
274 auto format(const jami::rational<I>& r, FormatContext& ctx) const -> decltype(ctx.out())
275 {
276 return fmt::formatter<std::string_view>::format(r.to_string(), ctx);
277 }
278};
Naive implementation of the boost::rational interface, described here: https://www....
Definition rational.h:39
constexpr bool operator!() const
Definition rational.h:162
constexpr bool operator<(I i) const
Definition rational.h:182
constexpr rational & operator/=(const rational &r)
Definition rational.h:117
constexpr bool operator>(const rational &r) const
Definition rational.h:173
rational & operator=(I n)
Definition rational.h:68
constexpr rational operator-(const rational &r) const
Definition rational.h:96
constexpr const rational & operator--()
Definition rational.h:155
constexpr bool operator!=(I i) const
Definition rational.h:185
constexpr bool operator==(const rational &r) const
Definition rational.h:178
constexpr rational & operator-=(I i)
Definition rational.h:131
constexpr I denominator() const
Definition rational.h:86
constexpr R real() const
Definition rational.h:89
constexpr bool operator!=(const rational &r) const
Definition rational.h:179
constexpr bool operator==(I i) const
Definition rational.h:184
constexpr rational operator/(const rational &r) const
Definition rational.h:98
constexpr I numerator() const
Definition rational.h:85
constexpr rational(AVRational r)
Definition rational.h:58
constexpr rational & operator/=(I i)
Definition rational.h:142
constexpr bool operator<(const rational &r) const
Definition rational.h:168
constexpr rational()
Definition rational.h:42
constexpr rational & operator-=(const rational &r)
Definition rational.h:105
constexpr rational & operator*=(I i)
Definition rational.h:136
constexpr rational operator+(const rational &r) const
Definition rational.h:95
constexpr bool operator>(I i) const
Definition rational.h:183
constexpr rational(I n)
Definition rational.h:45
constexpr rational & operator*=(const rational &r)
Definition rational.h:110
constexpr rational & operator+=(const rational &r)
Definition rational.h:100
constexpr rational(I n, I d)
Definition rational.h:50
constexpr rational operator*(const rational &r) const
Definition rational.h:97
constexpr rational & operator+=(I i)
Definition rational.h:126
rational & assign(I n, I d)
Definition rational.h:76
constexpr const rational & operator++()
Definition rational.h:150
std::string to_string() const
Definition rational.h:63
rational< I > abs(const rational< I > &r)
Definition rational.h:233
void emitSignal(Args... args)
Definition jami_signal.h:64
rational< I > operator+(const rational< I > &r)
Definition rational.h:209
std::istream & operator>>(std::istream &is, rational< I > &r)
Definition rational.h:241
T rational_cast(const rational< I > &r)
rational< I > operator-(const rational< I > &r)
Definition rational.h:215
rational< I > operator/(II i, const rational< I > &r)
Definition rational.h:225
static std::ostream & operator<<(std::ostream &os, const Account &acc)
Definition account.h:512
auto format(const jami::rational< I > &r, FormatContext &ctx) const -> decltype(ctx.out())
Definition rational.h:274