GnuCash  4.11-517-g41de4cefce
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 
30 class GncNumeric;
31 enum class RoundType;
32 enum class DenomType;
33 
58 {
59 public:
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 
177 private:
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 
200 inline int cmp(GncRational a, GncRational b) { return a.cmp(b); }
201 inline int cmp(GncRational a, GncInt128 b) { return a.cmp(b); }
202 inline int cmp(GncInt128 a, GncRational b) { return GncRational(a, 1).cmp(b); }
203 
209 inline bool operator<(GncRational a, GncRational b) { return cmp(a, b) < 0; }
210 inline bool operator<(GncRational a, GncInt128 b) { return cmp(a, b) < 0; }
211 inline bool operator<(GncInt128 a, GncRational b) { return cmp(a, b) < 0; }
212 inline bool operator>(GncRational a, GncRational b) { return cmp(a, b) > 0; }
213 inline bool operator>(GncRational a, GncInt128 b) { return cmp(a, b) > 0; }
214 inline bool operator>(GncInt128 a, GncRational b) { return cmp(a, b) > 0; }
215 inline bool operator==(GncRational a, GncRational b) { return cmp(a, b) == 0; }
216 inline bool operator==(GncRational a, GncInt128 b) { return cmp(a, b) == 0; }
217 inline bool operator==(GncInt128 a, GncRational b) { return cmp(a, b) == 0; }
218 inline bool operator<=(GncRational a, GncRational b) { return cmp(a, b) <= 0; }
219 inline bool operator<=(GncRational a, GncInt128 b) { return cmp(a, b) <= 0; }
220 inline bool operator<=(GncInt128 a, GncRational b) { return cmp(a, b) <= 0; }
221 inline bool operator>=(GncRational a, GncRational b) { return cmp(a, b) >= 0; }
222 inline bool operator>=(GncRational a, GncInt128 b) { return cmp(a, b) >= 0; }
223 inline bool operator>=(GncInt128 a, GncRational b) { return cmp(a, b) >= 0; }
224 inline bool operator!=(GncRational a, GncRational b) { return cmp(a, b) != 0; }
225 inline bool operator!=(GncRational a, GncInt128 b) { return cmp(a, b) != 0; }
226 inline bool operator!=(GncInt128 a, GncRational b) { return cmp(a, b) != 0; }
242 GncRational operator+(GncRational a, GncRational b);
243 inline GncRational operator+(GncRational a, GncInt128 b)
244 {
245  return a + GncRational(b, 1);
246 }
247 inline GncRational operator+(GncInt128 a, GncRational b)
248 {
249  return GncRational(a, 1) + b;
250 }
251 GncRational operator-(GncRational a, GncRational b);
252 inline GncRational operator-(GncRational a, GncInt128 b)
253 {
254  return a - GncRational(b, 1);
255 }
256 inline GncRational operator-(GncInt128 a, GncRational b)
257 {
258  return GncRational(a, 1) - b;
259 }
260 GncRational operator*(GncRational a, GncRational b);
261 inline GncRational operator*(GncRational a, GncInt128 b)
262 {
263  return a * GncRational(b, 1);
264 }
265 inline GncRational operator*(GncInt128 a, GncRational b)
266 {
267  return GncRational(a, 1) * b;
268 }
269 GncRational operator/(GncRational a, GncRational b);
270 inline GncRational operator/(GncRational a, GncInt128 b)
271 {
272  return a / GncRational(b, 1);
273 }
274 inline GncRational operator/(GncInt128 a, GncRational b)
275 {
276  return GncRational(a, 1) / b;
277 }
278 
279 inline 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__
std::ostream & operator<<(std::ostream &ostr, RelativeDatePeriod per)
Add the display string to the provided std::ostream.
GncInt128 denom() const noexcept
Denominator accessor.
GncRational inv() const noexcept
Inverts the number, equivalent of /= {1, 1}.
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.
The primary numeric class for representing amounts and values.
Definition: gnc-numeric.hpp:59
GncRational convert(GncInt128 new_denom) const
Convert a GncRational to use a new denominator.
GncRational(GncInt128 num, GncInt128 den) noexcept
GncInt128 constructor.
GncRational abs() const noexcept
Absolute value; return value is always >= 0 and of same magnitude.
Rational number class using GncInt128 for the numerator and denominator.
GncRational round_to_numeric() const
Round to fit an int64_t, finding the closest possible approximation.
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.
GncInt128 num() const noexcept
Numerator accessor.
int cmp(GncRational b)
Compare function.
bool valid() const noexcept
Report if both members are valid numbers.
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:246
GncRational convert_sigfigs(unsigned int figs) const
Convert with the specified sigfigs.