GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-rational.hpp
1/********************************************************************
2 * gnc-rational.hpp - A rational number library *
3 * Copyright 2014 John Ralls <jralls@ceridwen.us> *
4 * This program is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU General Public License as *
6 * published by the Free Software Foundation; either version 2 of *
7 * the License, or (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, contact: *
16 * *
17 * Free Software Foundation Voice: +1-617-542-5942 *
18 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
19 * Boston, MA 02110-1301, USA gnu@gnu.org *
20 * *
21 *******************************************************************/
22
23#ifndef __GNC_RATIONAL_HPP__
24#define __GNC_RATIONAL_HPP__
25
26#include "gnc-numeric.h"
27#include "gnc-int128.hpp"
28#include "gnc-rational-rounding.hpp"
29
30class GncNumeric;
31enum class RoundType;
32enum class DenomType;
33
58{
59public:
63 GncRational() : m_num(0), m_den(1) {}
69 : m_num(num), m_den(den) {}
71 GncRational (gnc_numeric n) noexcept;
73 GncRational(GncNumeric n) noexcept;
74 GncRational(const GncRational& rhs) = default;
75 GncRational(GncRational&& rhs) = default;
76 GncRational& operator=(const GncRational& rhs) = default;
77 GncRational& operator=(GncRational&& rhs) = default;
78 ~GncRational() = default;
82 bool valid() const noexcept;
87 bool is_big() const noexcept;
89 operator gnc_numeric() const noexcept;
91 GncRational operator-() const noexcept;
98 GncRational reduce() const;
116 template <RoundType RT>
117 GncRational convert (GncInt128 new_denom) const
118 {
119 auto params = prepare_conversion(new_denom);
120 if (new_denom == GNC_DENOM_AUTO)
121 new_denom = m_den;
122 if (params.rem == 0)
123 return GncRational(params.num, new_denom);
124 return GncRational(round(params.num, params.den,
125 params.rem, RT2T<RT>()), new_denom);
126 }
127
139 template <RoundType RT>
140 GncRational convert_sigfigs(unsigned int figs) const
141 {
142 auto new_denom(sigfigs_denom(figs));
143 auto params = prepare_conversion(new_denom);
144 if (new_denom == 0) //It had better not, but just in case...
145 new_denom = 1;
146 if (params.rem == 0)
147 return GncRational(params.num, new_denom);
148 return GncRational(round(params.num, params.den,
149 params.rem, RT2T<RT>()), new_denom);
150 }
151
153 GncInt128 num() const noexcept { return m_num; }
155 GncInt128 denom() const noexcept { return m_den; }
160 void operator+=(GncRational b);
161 void operator-=(GncRational b);
162 void operator*=(GncRational b);
163 void operator/=(GncRational b);
166 GncRational inv() const noexcept;
168 GncRational abs() const noexcept;
174 int cmp(GncRational b);
175 int cmp(GncInt128 b) { return cmp(GncRational(b, 1)); }
176
177private:
178 struct round_param
179 {
180 GncInt128 num;
181 GncInt128 den;
182 GncInt128 rem;
183 };
184 /* Calculates the denominator required to convert to figs sigfigs. Note that
185 * it uses the same powten function that the GncNumeric version does because
186 * 17 significant figures should be plenty.
187 */
188 GncInt128 sigfigs_denom(unsigned figs) const noexcept;
189 /* Calculates a round_param struct to pass to a rounding function that will
190 * finish computing a GncNumeric with the new denominator.
191 */
192 round_param prepare_conversion(GncInt128 new_denom) const;
193 GncInt128 m_num;
194 GncInt128 m_den;
195};
196
200inline int cmp(GncRational a, GncRational b) { return a.cmp(b); }
201inline int cmp(GncRational a, GncInt128 b) { return a.cmp(b); }
202inline int cmp(GncInt128 a, GncRational b) { return GncRational(a, 1).cmp(b); }
203
209inline bool operator<(GncRational a, GncRational b) { return cmp(a, b) < 0; }
210inline bool operator<(GncRational a, GncInt128 b) { return cmp(a, b) < 0; }
211inline bool operator<(GncInt128 a, GncRational b) { return cmp(a, b) < 0; }
212inline bool operator>(GncRational a, GncRational b) { return cmp(a, b) > 0; }
213inline bool operator>(GncRational a, GncInt128 b) { return cmp(a, b) > 0; }
214inline bool operator>(GncInt128 a, GncRational b) { return cmp(a, b) > 0; }
215inline bool operator==(GncRational a, GncRational b) { return cmp(a, b) == 0; }
216inline bool operator==(GncRational a, GncInt128 b) { return cmp(a, b) == 0; }
217inline bool operator==(GncInt128 a, GncRational b) { return cmp(a, b) == 0; }
218inline bool operator<=(GncRational a, GncRational b) { return cmp(a, b) <= 0; }
219inline bool operator<=(GncRational a, GncInt128 b) { return cmp(a, b) <= 0; }
220inline bool operator<=(GncInt128 a, GncRational b) { return cmp(a, b) <= 0; }
221inline bool operator>=(GncRational a, GncRational b) { return cmp(a, b) >= 0; }
222inline bool operator>=(GncRational a, GncInt128 b) { return cmp(a, b) >= 0; }
223inline bool operator>=(GncInt128 a, GncRational b) { return cmp(a, b) >= 0; }
224inline bool operator!=(GncRational a, GncRational b) { return cmp(a, b) != 0; }
225inline bool operator!=(GncRational a, GncInt128 b) { return cmp(a, b) != 0; }
226inline bool operator!=(GncInt128 a, GncRational b) { return cmp(a, b) != 0; }
242GncRational operator+(GncRational a, GncRational b);
243inline GncRational operator+(GncRational a, GncInt128 b)
244{
245 return a + GncRational(b, 1);
246}
247inline GncRational operator+(GncInt128 a, GncRational b)
248{
249 return GncRational(a, 1) + b;
250}
251GncRational operator-(GncRational a, GncRational b);
252inline GncRational operator-(GncRational a, GncInt128 b)
253{
254 return a - GncRational(b, 1);
255}
256inline GncRational operator-(GncInt128 a, GncRational b)
257{
258 return GncRational(a, 1) - b;
259}
260GncRational operator*(GncRational a, GncRational b);
261inline GncRational operator*(GncRational a, GncInt128 b)
262{
263 return a * GncRational(b, 1);
264}
265inline GncRational operator*(GncInt128 a, GncRational b)
266{
267 return GncRational(a, 1) * b;
268}
269GncRational operator/(GncRational a, GncRational b);
270inline GncRational operator/(GncRational a, GncInt128 b)
271{
272 return a / GncRational(b, 1);
273}
274inline GncRational operator/(GncInt128 a, GncRational b)
275{
276 return GncRational(a, 1) / b;
277}
278
279inline std::ostream& operator<<(std::ostream& stream, const GncRational& val) noexcept
280{
281 stream << val.num() << "/" << val.denom();
282 return stream;
283}
285#endif //__GNC_RATIONAL_HPP__
The primary numeric class for representing amounts and values.
Rational number class using GncInt128 for the numerator and denominator.
bool valid() const noexcept
Report if both members are valid numbers.
GncRational abs() const noexcept
Absolute value; return value is always >= 0 and of same magnitude.
GncRational inv() const noexcept
Inverts the number, equivalent of /= {1, 1}.
GncInt128 denom() const noexcept
Denominator accessor.
GncInt128 num() const noexcept
Numerator accessor.
GncRational()
Default constructor provides the zero value.
bool is_big() const noexcept
Report if either numerator or denominator are too big to fit in an int64_t.
GncRational round_to_numeric() const
Round to fit an int64_t, finding the closest possible approximation.
GncRational(GncInt128 num, GncInt128 den) noexcept
GncInt128 constructor.
int cmp(GncRational b)
Compare function.
GncRational convert(GncInt128 new_denom) const
Convert a GncRational to use a new denominator.
GncRational convert_sigfigs(unsigned int figs) const
Convert with the specified sigfigs.
GncRational reduce() const
Return an equivalent fraction with all common factors between the numerator and the denominator remov...
An exact-rational-number library for gnucash.
#define GNC_DENOM_AUTO
Values that can be passed as the 'denom' argument.