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