GnuCash  5.6-150-g038405b370+
gnc-numeric.cpp
1 /********************************************************************
2  * gnc-numeric.c -- an exact-number library for accounting use *
3  * Copyright (C) 2000 Bill Gribble *
4  * Copyright (C) 2004 Linas Vepstas <linas@linas.org> *
5  * *
6  * This program is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU General Public License as *
8  * published by the Free Software Foundation; either version 2 of *
9  * the License, or (at your option) any later version. *
10  * *
11  * This program is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14  * GNU General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU General Public License*
17  * along with this program; if not, contact: *
18  * *
19  * Free Software Foundation Voice: +1-617-542-5942 *
20  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21  * Boston, MA 02110-1301, USA gnu@gnu.org *
22  * *
23  *******************************************************************/
24 
25 #include <glib.h>
26 
27 #include <cmath>
28 #include <cstdio>
29 #include <cstdlib>
30 #include <cstring>
31 #include <cstdint>
32 #include <sstream>
33 #include <boost/regex.hpp>
34 #include <boost/regex/icu.hpp>
35 #include <boost/locale/encoding_utf.hpp>
36 
37 #include <config.h>
38 #include <stdexcept>
39 #include <stdint.h>
40 #include "gnc-int128.hpp"
41 #include "qof.h"
42 
43 #include "gnc-numeric.hpp"
44 #include "gnc-rational.hpp"
45 
46 #include <optional>
47 #include <charconv>
48 
49 static QofLogModule log_module = "qof";
50 
51 static const uint8_t max_leg_digits{18};
52 static const int64_t pten[] = { 1, 10, 100, 1000, 10000, 100000, 1000000,
53  10000000, 100000000, 1000000000,
54  INT64_C(10000000000), INT64_C(100000000000),
55  INT64_C(1000000000000), INT64_C(10000000000000),
56  INT64_C(100000000000000),
57  INT64_C(1000000000000000),
58  INT64_C(10000000000000000),
59  INT64_C(100000000000000000),
60  INT64_C(1000000000000000000)};
61 #define POWTEN_OVERFLOW -5
62 
63 int64_t
64 powten (unsigned int exp)
65 {
66  if (exp > max_leg_digits)
67  exp = max_leg_digits;
68  return pten[exp];
69 }
70 
72 {
73  /* Can't use isValid here because we want to throw different exceptions. */
74  if (rr.num().isNan() || rr.denom().isNan())
75  throw std::underflow_error("Operation resulted in NaN.");
76  if (rr.num().isOverflow() || rr.denom().isOverflow())
77  throw std::overflow_error("Operation overflowed a 128-bit int.");
78  if (rr.num().isBig() || rr.denom().isBig())
79  {
80  GncRational reduced(rr.reduce());
81  rr = reduced.round_to_numeric(); // A no-op if it's already small.
82  }
83  m_num = static_cast<int64_t>(rr.num());
84  m_den = static_cast<int64_t>(rr.denom());
85 }
86 
87 GncNumeric::GncNumeric(double d) : m_num(0), m_den(1)
88 {
89  static uint64_t max_leg_value{INT64_C(1000000000000000000)};
90  if (std::isnan(d) || fabs(d) > max_leg_value)
91  {
92  std::ostringstream msg;
93  msg << "Unable to construct a GncNumeric from " << d << ".\n";
94  throw std::invalid_argument(msg.str());
95  }
96  constexpr auto max_num = static_cast<double>(INT64_MAX);
97  auto logval = log10(fabs(d));
98  int64_t den;
99  uint8_t den_digits;
100  if (logval > 0.0)
101  den_digits = (max_leg_digits + 1) - static_cast<int>(floor(logval));
102  else
103  den_digits = max_leg_digits;
104  den = powten(den_digits);
105  auto num_d = static_cast<double>(den) * d;
106  while (fabs(num_d) > max_num && den_digits > 1)
107  {
108  den = powten(--den_digits);
109  num_d = static_cast<double>(den) * d;
110  }
111  auto num = static_cast<int64_t>(floor(num_d));
112 
113  if (num == 0)
114  return;
115  GncNumeric q(num, den);
116  auto r = q.reduce();
117  m_num = r.num();
118  m_den = r.denom();
119 }
120 
121 using boost::regex;
122 using boost::u32regex;
123 using boost::regex_search;
124 using boost::u32regex_search;
125 using boost::smatch;
126 
127 
128 static std::pair<int64_t, int64_t>
129 reduce_number_pair(std::pair<GncInt128, GncInt128>num_pair,
130  const std::string& num_str, bool autoround)
131 {
132  auto [n, d] = num_pair;
133  if (!autoround && n.isBig()) {
134  std::ostringstream errmsg;
135  errmsg << "Decimal string " << num_str
136  << "can't be represented in a GncNumeric without rounding.";
137  throw std::overflow_error(errmsg.str());
138  }
139  while (n.isBig() && d > 0) {
140  n >>= 1;
141  d >>= 1;
142  }
143  if (n.isBig()) // Shouldn't happen, of course
144  {
145  std::ostringstream errmsg;
146  errmsg << "Decimal string " << num_str
147  << " can't be represented in a GncNumeric, even after reducing "
148  "denom to "
149  << d;
150  throw std::overflow_error(errmsg.str());
151  }
152  return std::make_pair(static_cast<int64_t>(n), static_cast<int64_t>(d));
153 }
154 
155 static std::pair<GncInt128, int64_t>
156 numeric_from_decimal_match(const std::string& integer, const std::string& decimal)
157 {
158  auto neg = (!integer.empty() && integer[0] == '-');
159  GncInt128 high((neg && integer.length() > 1) || (!neg && !integer.empty())
160  ? stoll(integer)
161  : 0);
162  GncInt128 low{ decimal.empty() ? 0 : stoll(decimal)};
163  auto exp10 = decimal.length();
164  int64_t d = powten(exp10);
165  GncInt128 n = high * d + (neg ? -low : low);
166  while (exp10 > max_leg_digits) {
167  /* If the arg to powten is bigger than max_leg_digits
168  it returns 10**max_leg_digits so reduce exp10 by
169  that amount */
170  n = n / powten(exp10 - max_leg_digits);
171  exp10 -= max_leg_digits;
172  }
173  return std::make_pair(n, d);
174 }
175 
176 static std::pair<GncInt128, GncInt128>
177 numeric_from_scientific_match(smatch &m)
178 {
179  int exp{m[4].matched ? stoi(m[4].str()) : 0};
180  auto neg_exp{exp < 0};
181  exp = neg_exp ? -exp : exp;
182  if (exp >= max_leg_digits)
183  {
184  std::ostringstream errmsg;
185  errmsg << "Exponent " << m[3].str() << " in match " << m[0].str()
186  << " exceeds range that GnuCash can parse.";
187  throw std::overflow_error(errmsg.str());
188  }
189 
190  GncInt128 num, denom;
191  auto mult = powten(exp);
192 
193  if (m[1].matched)
194  {
195  denom = neg_exp ? mult : 1;
196  num = neg_exp ? stoll(m[1].str()) : mult * stoll(m[1].str());
197  }
198  else
199  {
200  auto [d_num, d_denom] = numeric_from_decimal_match(m[2].str(), m[3].str());
201 
202  if (neg_exp || d_denom > mult)
203  {
204  num = d_num;
205  denom = neg_exp ? d_denom * mult : d_denom / mult;
206  }
207  else
208  {
209  num = d_num * mult / d_denom;
210  denom = 1;
211  }
212  }
213  return std::make_pair(num, denom);
214 }
215 
216 static std::optional<gnc_numeric>
217 fast_numeral_rational (const char* str)
218 {
219  if (!str || !str[0])
220  return {};
221 
222  // because minint64 = -9223372036854775808 and has 20 characters,
223  // the maximum strlen to handle is 20+19+1 = 40. 48 is a nice
224  // number in 64-bit.
225  auto end_ptr{(const char*)memchr (str, '\0', 48)};
226  if (!end_ptr)
227  return {};
228 
229  int64_t num, denom{};
230  auto result = std::from_chars (str, end_ptr, num);
231  if (result.ec != std::errc())
232  return {};
233 
234  if (result.ptr == end_ptr)
235  return gnc_numeric_create (num, 1);
236 
237  if (*result.ptr != '/')
238  return {};
239 
240  result = std::from_chars (result.ptr + 1, end_ptr, denom);
241  if (result.ec != std::errc() || result.ptr != end_ptr || denom <= 0)
242  return {};
243 
244  return gnc_numeric_create (num, denom);
245 }
246 
247 GncNumeric::GncNumeric(const std::string &str, bool autoround) {
248  static const std::string begin("^[^-.0-9]*");
249  static const std::string end("[^0-9]*$");
250  static const std::string begin_group("(?:");
251  static const std::string end_group(")");
252  static const std::string or_op("|");
253  static const std::string maybe_sign ("(-?)");
254  static const std::string opt_signed_int("(-?[0-9]*)");
255  static const std::string opt_signed_separated_int("(-?[0-9]{1,3})");
256  static const std::string unsigned_int("([0-9]+)");
257  static const std::string eu_separated_int("(?:[[:space:]'.]([0-9]{3}))?");
258  static const std::string en_separated_int("(?:\\,([0-9]{3}))?");
259  static const std::string eu_decimal_part("(?:\\,([0-9]+))?");
260  static const std::string en_decimal_part("(?:\\.([0-9]+))?");
261  static const std::string hex_frag("(0[xX][A-Fa-f0-9]+)");
262  static const std::string slash("[ \\t]*/[ \\t]*");
263  static const std::string whitespace("[ \\t]+");
264  static const std::string eu_sep_decimal(begin_group + opt_signed_separated_int + eu_separated_int + eu_separated_int + eu_separated_int + eu_separated_int + eu_decimal_part + end_group);
265  static const std::string en_sep_decimal(begin_group + opt_signed_separated_int + en_separated_int + en_separated_int + en_separated_int + en_separated_int + en_decimal_part + end_group);
266  /* The llvm standard C++ library refused to recognize the - in the
267  * opt_signed_int pattern with the default ECMAScript syntax so we use the
268  * awk syntax.
269  */
270  static const regex numeral(begin + opt_signed_int + end);
271  static const regex hex(begin + hex_frag + end);
272  static const regex numeral_rational(begin + opt_signed_int + slash + unsigned_int + end);
273  static const regex integer_and_fraction(begin + maybe_sign + unsigned_int + whitespace + unsigned_int + slash + unsigned_int + end);
274  static const regex hex_rational(begin + hex_frag + slash + hex_frag + end);
275  static const regex hex_over_num(begin + hex_frag + slash + unsigned_int + end);
276  static const regex num_over_hex(begin + opt_signed_int + slash + hex_frag + end);
277  static const regex decimal(begin + opt_signed_int + "[.,]" + unsigned_int + end);
278  static const u32regex sep_decimal =
279  boost::make_u32regex(begin + begin_group + eu_sep_decimal + or_op + en_sep_decimal + end_group + end);
280  static const regex scientific("(?:(-?[0-9]+[.,]?)|(-?[0-9]*)[.,]([0-9]+))[Ee](-?[0-9]+)");
281  static const regex has_hex_prefix(".*0[xX]$");
282  smatch m, x;
283  /* The order of testing the regexes is from the more restrictve to the less
284  * restrictive, as less-restrictive ones will match patterns that would also
285  * match the more-restrictive and so invoke the wrong construction.
286  */
287  if (str.empty())
288  throw std::invalid_argument(
289  "Can't construct a GncNumeric from an empty string.");
290  if (auto res = fast_numeral_rational (str.c_str()))
291  {
292  m_num = res->num;
293  m_den = res->denom;
294  return;
295  }
296  if (regex_search(str, m, hex_rational))
297  {
298  GncNumeric n(stoll(m[1].str(), nullptr, 16),
299  stoll(m[2].str(), nullptr, 16));
300 
301  m_num = n.num();
302  m_den = n.denom();
303  return;
304  }
305  if (regex_search(str, m, hex_over_num))
306  {
307  GncNumeric n(stoll(m[1].str(), nullptr, 16), stoll(m[2].str()));
308  m_num = n.num();
309  m_den = n.denom();
310  return;
311  }
312  if (regex_search(str, m, num_over_hex))
313  {
314  GncNumeric n(stoll(m[1].str()), stoll(m[2].str(), nullptr, 16));
315  m_num = n.num();
316  m_den = n.denom();
317  return;
318  }
319  if (regex_search(str, m, integer_and_fraction))
320  {
321  GncNumeric n(stoll(m[3].str()), stoll(m[4].str()));
322  n += stoll(m[2].str());
323  m_num = m[1].str().empty() ? n.num() : -n.num();
324  m_den = n.denom();
325  return;
326  }
327  if (regex_search(str, m, numeral_rational))
328  {
329  GncNumeric n(stoll(m[1].str()), stoll(m[2].str()));
330  m_num = n.num();
331  m_den = n.denom();
332  return;
333  }
334  if (regex_search(str, m, scientific) && ! regex_match(m.prefix().str(), x, has_hex_prefix))
335  {
336  auto [num, denom] =
337  reduce_number_pair(numeric_from_scientific_match(m),
338  str, autoround);
339  m_num = num;
340  m_den = denom;
341  return;
342  }
343  if (regex_search(str, m, decimal))
344  {
345  std::string integer{m[1].matched ? m[1].str() : ""};
346  std::string decimal{m[2].matched ? m[2].str() : ""};
347  auto [num, denom] = reduce_number_pair(numeric_from_decimal_match(integer, decimal), str, autoround);
348  m_num = num;
349  m_den = denom;
350  return;
351  }
352  if (u32regex_search(str, m, sep_decimal))
353  {
354  /* There's a bit of magic here because of the complexity of
355  * the regex. It supports two formats, one for locales that
356  * use space, apostrophe, or dot for thousands separator and
357  * comma for decimal separator and the other for locales that
358  * use comma for thousands and dot for decimal. For each
359  * format there are 5 captures for thousands-groups (allowing
360  * up to 10^16 - 1) and one for decimal, hence the loops from
361  * 1 - 5 and 7 - 11 with the decimal being either capture 6 or
362  * capture 12.
363  */
364  std::string integer(""), decimal("");
365  for (auto i{1}; i < 6; ++i)
366  if (m[i].matched)
367  integer += m[i].str();
368  if (m[6].matched)
369  decimal += m[6].str();
370  if (integer.empty() && decimal.empty())
371  {
372  for (auto i{7}; i <12; ++i)
373  if (m[i].matched)
374  integer += m[i].str();
375  if (m[12].matched)
376  decimal += m[12].str();
377  }
378  auto [num, denom] =
379  reduce_number_pair(numeric_from_decimal_match(integer, decimal),
380  str, autoround);
381  m_num = num;
382  m_den = denom;
383  return;
384  }
385  if (regex_search(str, m, hex))
386  {
387  GncNumeric n(stoll(m[1].str(), nullptr, 16), INT64_C(1));
388  m_num = n.num();
389  m_den = n.denom();
390  return;
391  }
392  if (regex_search(str, m, numeral))
393  {
394  GncNumeric n(stoll(m[1].str()), INT64_C(1));
395  m_num = n.num();
396  m_den = n.denom();
397  return;
398  }
399  std::ostringstream errmsg;
400  errmsg << "String " << str << " contains no recognizable numeric value.";
401  throw std::invalid_argument(errmsg.str());
402 }
403 
404 GncNumeric::operator gnc_numeric() const noexcept
405 {
406  return {m_num, m_den};
407 }
408 
409 GncNumeric::operator double() const noexcept
410 {
411  return static_cast<double>(m_num) / static_cast<double>(m_den);
412 }
413 
415 GncNumeric::operator-() const noexcept
416 {
417  GncNumeric b(*this);
418  b.m_num = - b.m_num;
419  return b;
420 }
421 
423 GncNumeric::inv() const noexcept
424 {
425  if (m_num == 0)
426  return *this;
427  if (m_num < 0)
428  return GncNumeric(-m_den, -m_num);
429  return GncNumeric(m_den, m_num);
430 }
431 
433 GncNumeric::abs() const noexcept
434 {
435  if (m_num < 0)
436  return -*this;
437  return *this;
438 }
439 
441 GncNumeric::reduce() const noexcept
442 {
443  return static_cast<GncNumeric>(GncRational(*this).reduce());
444 }
445 
446 GncNumeric::round_param
447 GncNumeric::prepare_conversion(int64_t new_denom) const
448 {
449  if (new_denom == m_den || new_denom == GNC_DENOM_AUTO)
450  return {m_num, m_den, 0};
451  GncRational conversion(new_denom, m_den);
452  auto red_conv = conversion.reduce();
453  GncInt128 old_num(m_num);
454  auto new_num = old_num * red_conv.num();
455  auto rem = new_num % red_conv.denom();
456  new_num /= red_conv.denom();
457  if (new_num.isBig())
458  {
459  GncRational rr(new_num, new_denom);
460  GncNumeric nn(rr);
461  rr = rr.convert<RoundType::truncate>(new_denom);
462  return {static_cast<int64_t>(rr.num()), new_denom, 0};
463  }
464  return {static_cast<int64_t>(new_num),
465  static_cast<int64_t>(red_conv.denom()), static_cast<int64_t>(rem)};
466 }
467 
468 int64_t
469 GncNumeric::sigfigs_denom(unsigned figs) const noexcept
470 {
471  if (m_num == 0)
472  return 1;
473 
474  int64_t num_abs{std::abs(m_num)};
475  bool not_frac = num_abs > m_den;
476  int64_t val{ not_frac ? num_abs / m_den : m_den / num_abs };
477  unsigned digits{};
478  while (val >= 10)
479  {
480  ++digits;
481  val /= 10;
482  }
483  return not_frac ?
484  powten(digits < figs ? figs - digits - 1 : 0) :
485  powten(figs + digits);
486 }
487 
488 std::string
489 GncNumeric::to_string() const noexcept
490 {
491  std::ostringstream out;
492  out << *this;
493  return out.str();
494 }
495 
496 bool
497 GncNumeric::is_decimal() const noexcept
498 {
499  for (unsigned pwr = 0; pwr < max_leg_digits && m_den >= pten[pwr]; ++pwr)
500  {
501  if (m_den == pten[pwr])
502  return true;
503  if (m_den % pten[pwr])
504  return false;
505  }
506  return false;
507 }
508 
510 GncNumeric::to_decimal(unsigned int max_places) const
511 {
512  if (max_places > max_leg_digits)
513  max_places = max_leg_digits;
514 
515  if (m_num == 0)
516  return GncNumeric();
517 
518  if (is_decimal())
519  {
520  if (m_num == 0 || m_den < powten(max_places))
521  return *this; // Nothing to do.
522  /* See if we can reduce m_num to fit in max_places */
523  auto excess = m_den / powten(max_places);
524  if (m_num % excess)
525  {
526  std::ostringstream msg;
527  msg << "GncNumeric " << *this
528  << " could not be represented in " << max_places
529  << " decimal places without rounding.\n";
530  throw std::range_error(msg.str());
531  }
532  return GncNumeric(m_num / excess, powten(max_places));
533  }
534  GncRational rr(*this);
535  rr = rr.convert<RoundType::never>(powten(max_places)); //May throw
536  /* rr might have gotten reduced a bit too much; if so, put it back: */
537  unsigned int pwr{1};
538  for (; pwr <= max_places && !(rr.denom() % powten(pwr)); ++pwr);
539  auto reduce_to = powten(pwr);
540  GncInt128 rr_num(rr.num()), rr_den(rr.denom());
541  if (rr_den % reduce_to)
542  {
543  auto factor(reduce_to / rr.denom());
544  rr_num *= factor;
545  rr_den *= factor;
546  }
547  while (!rr_num.isZero() && rr_num > 9 && rr_den > 9 && rr_num % 10 == 0)
548  {
549  rr_num /= 10;
550  rr_den /= 10;
551  }
552  try
553  {
554  /* Construct from the parts to avoid the GncRational constructor's
555  * automatic rounding.
556  */
557  return {static_cast<int64_t>(rr_num), static_cast<int64_t>(rr_den)};
558  }
559  catch (const std::invalid_argument& err)
560  {
561  std::ostringstream msg;
562  msg << "GncNumeric " << *this
563  << " could not be represented as a decimal without rounding.\n";
564  throw std::range_error(msg.str());
565  }
566  catch (const std::overflow_error& err)
567  {
568  std::ostringstream msg;
569  msg << "GncNumeric " << *this
570  << " overflows when attempting to convert it to decimal.\n";
571  throw std::range_error(msg.str());
572  }
573  catch (const std::underflow_error& err)
574  {
575  std::ostringstream msg;
576  msg << "GncNumeric " << *this
577  << " underflows when attempting to convert it to decimal.\n";
578  throw std::range_error(msg.str());
579  }
580 }
581 
582 void
583 GncNumeric::operator+=(GncNumeric b)
584 {
585  *this = *this + b;
586 }
587 
588 void
589 GncNumeric::operator-=(GncNumeric b)
590 {
591  *this = *this - b;
592 }
593 
594 void
595 GncNumeric::operator*=(GncNumeric b)
596 {
597  *this = *this * b;
598 }
599 
600 void
601 GncNumeric::operator/=(GncNumeric b)
602 {
603  *this = *this / b;
604 }
605 
606 int
607 GncNumeric::cmp(GncNumeric b)
608 {
609  if (m_den == b.denom())
610  {
611  auto b_num = b.num();
612  return m_num < b_num ? -1 : b_num < m_num ? 1 : 0;
613  }
614  GncRational an(*this), bn(b);
615  return an.cmp(bn);
616 }
617 
619 operator+(GncNumeric a, GncNumeric b)
620 {
621  if (a.num() == 0)
622  return b;
623  if (b.num() == 0)
624  return a;
625  GncRational ar(a), br(b);
626  auto rr = ar + br;
627  return static_cast<GncNumeric>(rr);
628 }
629 
631 operator-(GncNumeric a, GncNumeric b)
632 {
633  return a + (-b);
634 }
635 
637 operator*(GncNumeric a, GncNumeric b)
638 {
639  if (a.num() == 0 || b.num() == 0)
640  {
641  GncNumeric retval;
642  return retval;
643  }
644  GncRational ar(a), br(b);
645  auto rr = ar * br;
646  return static_cast<GncNumeric>(rr);
647 }
648 
650 operator/(GncNumeric a, GncNumeric b)
651 {
652  if (a.num() == 0)
653  {
654  GncNumeric retval;
655  return retval;
656  }
657  if (b.num() == 0)
658  throw std::underflow_error("Attempt to divide by zero.");
659 
660  GncRational ar(a), br(b);
661  auto rr = ar / br;
662  return static_cast<GncNumeric>(rr);
663 }
664 
665 template <typename T, typename I> T
666 convert(T num, I new_denom, int how)
667 {
668  auto rtype = static_cast<RoundType>(how & GNC_NUMERIC_RND_MASK);
669  unsigned int figs = GNC_HOW_GET_SIGFIGS(how);
670 
671  auto dtype = static_cast<DenomType>(how & GNC_NUMERIC_DENOM_MASK);
672  bool sigfigs = dtype == DenomType::sigfigs;
673  if (dtype == DenomType::reduce)
674  num = num.reduce();
675 
676  switch (rtype)
677  {
678  case RoundType::floor:
679  if (sigfigs)
680  return num.template convert_sigfigs<RoundType::floor>(figs);
681  else
682  return num.template convert<RoundType::floor>(new_denom);
683  case RoundType::ceiling:
684  if (sigfigs)
685  return num.template convert_sigfigs<RoundType::ceiling>(figs);
686  else
687  return num.template convert<RoundType::ceiling>(new_denom);
688  case RoundType::truncate:
689  if (sigfigs)
690  return num.template convert_sigfigs<RoundType::truncate>(figs);
691  else
692  return num.template convert<RoundType::truncate>(new_denom);
693  case RoundType::promote:
694  if (sigfigs)
695  return num.template convert_sigfigs<RoundType::promote>(figs);
696  else
697  return num.template convert<RoundType::promote>(new_denom);
698  case RoundType::half_down:
699  if (sigfigs)
700  return num.template convert_sigfigs<RoundType::half_down>(figs);
701  else
702  return num.template convert<RoundType::half_down>(new_denom);
703  case RoundType::half_up:
704  if (sigfigs)
705  return num.template convert_sigfigs<RoundType::half_up>(figs);
706  else
707  return num.template convert<RoundType::half_up>(new_denom);
708  case RoundType::bankers:
709  if (sigfigs)
710  return num.template convert_sigfigs<RoundType::bankers>(figs);
711  else
712  return num.template convert<RoundType::bankers>(new_denom);
713  case RoundType::never:
714  if (sigfigs)
715  return num.template convert_sigfigs<RoundType::never>(figs);
716  else
717  return num.template convert<RoundType::never>(new_denom);
718  default:
719  /* round-truncate just returns the numerator unchanged. The old
720  * gnc-numeric convert had no "default" behavior at rounding that
721  * had the same result, but we need to make it explicit here to
722  * run the rest of the conversion code.
723  */
724  if (sigfigs)
725  return num.template convert_sigfigs<RoundType::truncate>(figs);
726  else
727  return num.template convert<RoundType::truncate>(new_denom);
728 
729  }
730 }
731 
732 /* =============================================================== */
733 /* This function is small, simple, and used everywhere below,
734  * lets try to inline it.
735  */
737 gnc_numeric_check(gnc_numeric in)
738 {
739  if (G_LIKELY(in.denom != 0))
740  {
741  return GNC_ERROR_OK;
742  }
743  else if (in.num)
744  {
745  if ((0 < in.num) || (-4 > in.num))
746  {
747  in.num = (gint64) GNC_ERROR_OVERFLOW;
748  }
749  return (GNCNumericErrorCode) in.num;
750  }
751  else
752  {
753  return GNC_ERROR_ARG;
754  }
755 }
756 
757 
758 /* *******************************************************************
759  * gnc_numeric_zero_p
760  ********************************************************************/
761 
762 gboolean
763 gnc_numeric_zero_p(gnc_numeric a)
764 {
765  if (gnc_numeric_check(a))
766  {
767  return 0;
768  }
769  else
770  {
771  if ((a.num == 0) && (a.denom != 0))
772  {
773  return 1;
774  }
775  else
776  {
777  return 0;
778  }
779  }
780 }
781 
782 /* *******************************************************************
783  * gnc_numeric_negative_p
784  ********************************************************************/
785 
786 gboolean
787 gnc_numeric_negative_p(gnc_numeric a)
788 {
789  if (gnc_numeric_check(a))
790  {
791  return 0;
792  }
793  else
794  {
795  if ((a.num < 0) && (a.denom != 0))
796  {
797  return 1;
798  }
799  else
800  {
801  return 0;
802  }
803  }
804 }
805 
806 /* *******************************************************************
807  * gnc_numeric_positive_p
808  ********************************************************************/
809 
810 gboolean
811 gnc_numeric_positive_p(gnc_numeric a)
812 {
813  if (gnc_numeric_check(a))
814  {
815  return 0;
816  }
817  else
818  {
819  if ((a.num > 0) && (a.denom != 0))
820  {
821  return 1;
822  }
823  else
824  {
825  return 0;
826  }
827  }
828 }
829 
830 
831 /* *******************************************************************
832  * gnc_numeric_compare
833  * returns 1 if a>b, -1 if b>a, 0 if a == b
834  ********************************************************************/
835 
836 int
837 gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
838 {
840  {
841  return 0;
842  }
843 
844  if (a.denom == b.denom)
845  {
846  if (a.num == b.num) return 0;
847  if (a.num > b.num) return 1;
848  return -1;
849  }
850 
851  GncNumeric an (a), bn (b);
852 
853  return an.cmp(bn);
854 }
855 
856 
857 /* *******************************************************************
858  * gnc_numeric_eq
859  ********************************************************************/
860 
861 gboolean
862 gnc_numeric_eq(gnc_numeric a, gnc_numeric b)
863 {
864  return ((a.num == b.num) && (a.denom == b.denom));
865 }
866 
867 
868 /* *******************************************************************
869  * gnc_numeric_equal
870  ********************************************************************/
871 
872 gboolean
873 gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
874 {
875  if (gnc_numeric_check(a))
876  {
877  /* a is not a valid number, check b */
878  if (gnc_numeric_check(b))
879  /* Both invalid, consider them equal */
880  return TRUE;
881  else
882  /* a invalid, b valid */
883  return FALSE;
884  }
885  if (gnc_numeric_check(b))
886  /* a valid, b invalid */
887  return FALSE;
888 
889  return gnc_numeric_compare (a, b) == 0;
890 }
891 
892 
893 /* *******************************************************************
894  * gnc_numeric_same
895  * would a and b be equal() if they were both converted to the same
896  * denominator?
897  ********************************************************************/
898 
899 int
900 gnc_numeric_same(gnc_numeric a, gnc_numeric b, gint64 denom,
901  gint how)
902 {
903  gnc_numeric aconv, bconv;
904 
905  aconv = gnc_numeric_convert(a, denom, how);
906  bconv = gnc_numeric_convert(b, denom, how);
907 
908  return(gnc_numeric_equal(aconv, bconv));
909 }
910 
911 static int64_t
912 denom_lcd(gnc_numeric a, gnc_numeric b, int64_t denom, int how)
913 {
914  if (denom == GNC_DENOM_AUTO &&
915  (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD)
916  {
917  GncInt128 ad(a.denom), bd(b.denom);
918  denom = static_cast<int64_t>(ad.lcm(bd));
919  }
920  return denom;
921 }
922 
923 /* *******************************************************************
924  * gnc_numeric_add
925  ********************************************************************/
926 
927 gnc_numeric
928 gnc_numeric_add(gnc_numeric a, gnc_numeric b,
929  gint64 denom, gint how)
930 {
932  {
934  }
935  try
936  {
937  denom = denom_lcd(a, b, denom, how);
938  if ((how & GNC_NUMERIC_DENOM_MASK) != GNC_HOW_DENOM_EXACT)
939  {
940  GncNumeric an (a), bn (b);
941  GncNumeric sum = an + bn;
942  return static_cast<gnc_numeric>(convert(sum, denom, how));
943  }
944  GncRational ar(a), br(b);
945  auto sum = ar + br;
946  if (denom == GNC_DENOM_AUTO &&
948  return static_cast<gnc_numeric>(sum.round_to_numeric());
949  sum = convert(sum, denom, how);
950  if (sum.is_big() || !sum.valid())
952  return static_cast<gnc_numeric>(sum);
953  }
954  catch (const std::overflow_error& err)
955  {
956  PWARN("%s", err.what());
958  }
959  catch (const std::invalid_argument& err)
960  {
961  PWARN("%s", err.what());
963  }
964  catch (const std::underflow_error& err)
965  {
966  PWARN("%s", err.what());
968  }
969  catch (const std::domain_error& err)
970  {
971  PWARN("%s", err.what());
973  }
974 }
975 
976 /* *******************************************************************
977  * gnc_numeric_sub
978  ********************************************************************/
979 
980 gnc_numeric
981 gnc_numeric_sub(gnc_numeric a, gnc_numeric b,
982  gint64 denom, gint how)
983 {
985  {
987  }
988  try
989  {
990  denom = denom_lcd(a, b, denom, how);
991  if ((how & GNC_NUMERIC_DENOM_MASK) != GNC_HOW_DENOM_EXACT)
992  {
993  GncNumeric an (a), bn (b);
994  auto sum = an - bn;
995  return static_cast<gnc_numeric>(convert(sum, denom, how));
996  }
997  GncRational ar(a), br(b);
998  auto sum = ar - br;
999  if (denom == GNC_DENOM_AUTO &&
1001  return static_cast<gnc_numeric>(sum.round_to_numeric());
1002  sum = convert(sum, denom, how);
1003  if (sum.is_big() || !sum.valid())
1005  return static_cast<gnc_numeric>(sum);
1006  }
1007  catch (const std::overflow_error& err)
1008  {
1009  PWARN("%s", err.what());
1011  }
1012  catch (const std::invalid_argument& err)
1013  {
1014  PWARN("%s", err.what());
1016  }
1017  catch (const std::underflow_error& err)
1018  {
1019  PWARN("%s", err.what());
1021  }
1022  catch (const std::domain_error& err)
1023  {
1024  PWARN("%s", err.what());
1026  }
1027 }
1028 
1029 /* *******************************************************************
1030  * gnc_numeric_mul
1031  ********************************************************************/
1032 
1033 gnc_numeric
1034 gnc_numeric_mul(gnc_numeric a, gnc_numeric b,
1035  gint64 denom, gint how)
1036 {
1037  if (gnc_numeric_check(a) || gnc_numeric_check(b))
1038  {
1040  }
1041 
1042  try
1043  {
1044  denom = denom_lcd(a, b, denom, how);
1045  if ((how & GNC_NUMERIC_DENOM_MASK) != GNC_HOW_DENOM_EXACT)
1046  {
1047  GncNumeric an (a), bn (b);
1048  auto prod = an * bn;
1049  return static_cast<gnc_numeric>(convert(prod, denom, how));
1050  }
1051  GncRational ar(a), br(b);
1052  auto prod = ar * br;
1053  if (denom == GNC_DENOM_AUTO &&
1055  return static_cast<gnc_numeric>(prod.round_to_numeric());
1056  prod = convert(prod, denom, how);
1057  if (prod.is_big() || !prod.valid())
1059  return static_cast<gnc_numeric>(prod);
1060  }
1061  catch (const std::overflow_error& err)
1062  {
1063  PWARN("%s", err.what());
1065  }
1066  catch (const std::invalid_argument& err)
1067  {
1068  PWARN("%s", err.what());
1070  }
1071  catch (const std::underflow_error& err)
1072  {
1073  PWARN("%s", err.what());
1075  }
1076  catch (const std::domain_error& err)
1077  {
1078  PWARN("%s", err.what());
1080  }
1081 }
1082 
1083 
1084 /* *******************************************************************
1085  * gnc_numeric_div
1086  ********************************************************************/
1087 
1088 gnc_numeric
1089 gnc_numeric_div(gnc_numeric a, gnc_numeric b,
1090  gint64 denom, gint how)
1091 {
1092  if (gnc_numeric_check(a) || gnc_numeric_check(b))
1093  {
1095  }
1096  try
1097  {
1098  denom = denom_lcd(a, b, denom, how);
1099  if ((how & GNC_NUMERIC_DENOM_MASK) != GNC_HOW_DENOM_EXACT)
1100  {
1101  GncNumeric an (a), bn (b);
1102  auto quot = an / bn;
1103  return static_cast<gnc_numeric>(convert(quot, denom, how));
1104  }
1105  GncRational ar(a), br(b);
1106  auto quot = ar / br;
1107  if (denom == GNC_DENOM_AUTO &&
1109  return static_cast<gnc_numeric>(quot.round_to_numeric());
1110  quot = static_cast<gnc_numeric>(convert(quot, denom, how));
1111  if (quot.is_big() || !quot.valid())
1113  return static_cast<gnc_numeric>(quot);
1114  }
1115  catch (const std::overflow_error& err)
1116  {
1117  PWARN("%s", err.what());
1119  }
1120  catch (const std::invalid_argument& err)
1121  {
1122  PWARN("%s", err.what());
1124  }
1125  catch (const std::underflow_error& err) //Divide by zero
1126  {
1127  PWARN("%s", err.what());
1129  }
1130  catch (const std::domain_error& err)
1131  {
1132  PWARN("%s", err.what());
1134  }
1135 }
1136 
1137 /* *******************************************************************
1138  * gnc_numeric_neg
1139  * negate the argument
1140  ********************************************************************/
1141 
1142 gnc_numeric
1143 gnc_numeric_neg(gnc_numeric a)
1144 {
1145  if (gnc_numeric_check(a))
1146  {
1148  }
1149  return gnc_numeric_create(- a.num, a.denom);
1150 }
1151 
1152 /* *******************************************************************
1153  * gnc_numeric_abs
1154  * return the absolute value of the argument
1155  ********************************************************************/
1156 
1157 gnc_numeric
1158 gnc_numeric_abs(gnc_numeric a)
1159 {
1160  if (gnc_numeric_check(a))
1161  {
1163  }
1164  return gnc_numeric_create(ABS(a.num), a.denom);
1165 }
1166 
1167 
1168 /* *******************************************************************
1169  * gnc_numeric_convert
1170  ********************************************************************/
1171 
1172 gnc_numeric
1173 gnc_numeric_convert(gnc_numeric in, int64_t denom, int how)
1174 {
1175  if (gnc_numeric_check(in))
1176  return in;
1177  try
1178  {
1179  return convert(GncNumeric(in), denom, how);
1180  }
1181  catch (const std::invalid_argument& err)
1182  {
1184  }
1185  catch (const std::overflow_error& err)
1186  {
1188  }
1189  catch (const std::underflow_error& err)
1190  {
1192  }
1193  catch (const std::domain_error& err)
1194  {
1196  }
1197 }
1198 
1199 
1200 /* *******************************************************************
1201  * reduce a fraction by GCF elimination. This is NOT done as a
1202  * part of the arithmetic API unless GNC_HOW_DENOM_REDUCE is specified
1203  * as the output denominator.
1204  ********************************************************************/
1205 
1206 gnc_numeric
1207 gnc_numeric_reduce(gnc_numeric in)
1208 {
1209  if (gnc_numeric_check(in))
1210  {
1212  }
1213 
1214  if (in.denom < 0) /* Negative denoms multiply num, can't be reduced. */
1215  return in;
1216  try
1217  {
1218  GncNumeric an (in);
1219  return static_cast<gnc_numeric>(an.reduce());
1220  }
1221  catch (const std::overflow_error& err)
1222  {
1223  PWARN("%s", err.what());
1225  }
1226  catch (const std::invalid_argument& err)
1227  {
1228  PWARN("%s", err.what());
1230  }
1231  catch (const std::underflow_error& err)
1232  {
1233  PWARN("%s", err.what());
1235  }
1236  catch (const std::domain_error& err)
1237  {
1238  PWARN("%s", err.what());
1240  }
1241 }
1242 
1243 
1244 /* *******************************************************************
1245  * gnc_numeric_to_decimal
1246  *
1247  * Attempt to convert the denominator to an exact power of ten without
1248  * rounding. TRUE is returned if 'a' has been converted or was already
1249  * decimal. Otherwise, FALSE is returned and 'a' remains unchanged.
1250  * The 'max_decimal_places' parameter may be NULL.
1251  ********************************************************************/
1252 
1253 gboolean
1254 gnc_numeric_to_decimal(gnc_numeric *a, guint8 *max_decimal_places)
1255 {
1256  int max_places = max_decimal_places == NULL ? max_leg_digits :
1257  *max_decimal_places;
1258  if (a->num == 0) return TRUE;
1259  try
1260  {
1261  GncNumeric an (*a);
1262  auto bn = an.to_decimal(max_places);
1263  *a = static_cast<gnc_numeric>(bn);
1264  return TRUE;
1265  }
1266  catch (const std::exception& err)
1267  {
1268  PINFO ("%s", err.what());
1269  return FALSE;
1270  }
1271 }
1272 
1273 
1274 gnc_numeric
1275 gnc_numeric_invert(gnc_numeric num)
1276 {
1277  if (num.num == 0)
1278  return gnc_numeric_zero();
1279  try
1280  {
1281  return static_cast<gnc_numeric>(GncNumeric(num).inv());
1282  }
1283  catch (const std::overflow_error& err)
1284  {
1285  PWARN("%s", err.what());
1287  }
1288  catch (const std::invalid_argument& err)
1289  {
1290  PWARN("%s", err.what());
1292  }
1293  catch (const std::underflow_error& err)
1294  {
1295  PWARN("%s", err.what());
1297  }
1298  catch (const std::domain_error& err)
1299  {
1300  PWARN("%s", err.what());
1302  }
1303 }
1304 
1305 /* *******************************************************************
1306  * double_to_gnc_numeric
1307  ********************************************************************/
1308 
1309 #ifdef _MSC_VER
1310 # define rint /* */
1311 #endif
1312 gnc_numeric
1313 double_to_gnc_numeric(double in, gint64 denom, gint how)
1314 {
1315  try
1316  {
1317  GncNumeric an(in);
1318  return convert(an, denom, how);
1319  }
1320  catch (const std::overflow_error& err)
1321  {
1322  PWARN("%s", err.what());
1324  }
1325  catch (const std::invalid_argument& err)
1326  {
1327  PWARN("%s", err.what());
1329  }
1330  catch (const std::underflow_error& err)
1331  {
1332  PWARN("%s", err.what());
1334  }
1335  catch (const std::domain_error& err)
1336  {
1337  PWARN("%s", err.what());
1339  }
1340 }
1341 
1342 /* *******************************************************************
1343  * gnc_numeric_to_double
1344  ********************************************************************/
1345 
1346 double
1347 gnc_numeric_to_double(gnc_numeric in)
1348 {
1349  if (in.denom > 0)
1350  {
1351  return (double)in.num / (double)in.denom;
1352  }
1353  else
1354  {
1355  return (double)(in.num * -in.denom);
1356  }
1357 }
1358 
1359 /* *******************************************************************
1360  * gnc_numeric_error
1361  ********************************************************************/
1362 
1363 gnc_numeric
1365 {
1366  return gnc_numeric_create(error_code, 0LL);
1367 }
1368 
1369 
1370 
1371 /* *******************************************************************
1372  * gnc_numeric text IO
1373  ********************************************************************/
1374 
1375 gchar *
1376 gnc_numeric_to_string(gnc_numeric n)
1377 {
1378  char *result;
1379  int64_t tmpnum = n.num;
1380  int64_t tmpdenom = n.denom;
1381 
1382  result = g_strdup_printf("%" PRId64 "/%" PRId64, tmpnum, tmpdenom);
1383 
1384  return result;
1385 }
1386 
1387 gchar *
1388 gnc_num_dbg_to_string(gnc_numeric n)
1389 {
1390  static char buff[1000];
1391  static char *p = buff;
1392  static const size_t size = 50;
1393  int64_t tmpnum = n.num;
1394  int64_t tmpdenom = n.denom;
1395 
1396  p += size;
1397  if ((size_t)(p - buff) > (sizeof(buff) - size))
1398  p = buff;
1399 
1400  snprintf(p, size, "%" PRId64 "/%" PRId64, tmpnum, tmpdenom);
1401 
1402  return p;
1403 }
1404 
1405 gnc_numeric
1406 gnc_numeric_from_string (const gchar* str)
1407 {
1408  if (!str)
1410 
1411  // the default gnc_numeric string format is "num/denom", whereby
1412  // the denom must be >= 1. this speedily parses it. this also
1413  // parses "num" as num/1.
1414  if (auto res = fast_numeral_rational (str))
1415  return *res;
1416 
1417  try
1418  {
1419  return GncNumeric (str);
1420  }
1421  catch (const std::exception& err)
1422  {
1423  PWARN("%s", err.what());
1425  }
1426 }
1427 
1428 /* *******************************************************************
1429  * GValue handling
1430  ********************************************************************/
1431 static gnc_numeric*
1432 gnc_numeric_boxed_copy_func( gnc_numeric *in_gnc_numeric )
1433 {
1434  if (!in_gnc_numeric)
1435  return nullptr;
1436 
1437  /* newvalue will be passed to g_free so we must allocate with g_malloc. */
1438  auto newvalue = static_cast<gnc_numeric*>(g_malloc (sizeof (gnc_numeric)));
1439  *newvalue = *in_gnc_numeric;
1440 
1441  return newvalue;
1442 }
1443 
1444 static void
1445 gnc_numeric_boxed_free_func( gnc_numeric *in_gnc_numeric )
1446 {
1447  g_free( in_gnc_numeric );
1448 }
1449 
1450 G_DEFINE_BOXED_TYPE (gnc_numeric, gnc_numeric, gnc_numeric_boxed_copy_func, gnc_numeric_boxed_free_func)
1451 
1452 /* *******************************************************************
1453  * gnc_numeric misc testing
1454  ********************************************************************/
1455 #ifdef _GNC_NUMERIC_TEST
1456 
1457 static char *
1458 gnc_numeric_print(gnc_numeric in)
1459 {
1460  char * retval;
1461  if (gnc_numeric_check(in))
1462  {
1463  retval = g_strdup_printf("<ERROR> [%" G_GINT64_FORMAT " / %" G_GINT64_FORMAT "]",
1464  in.num,
1465  in.denom);
1466  }
1467  else
1468  {
1469  retval = g_strdup_printf("[%" G_GINT64_FORMAT " / %" G_GINT64_FORMAT "]",
1470  in.num,
1471  in.denom);
1472  }
1473  return retval;
1474 }
1475 
1476 int
1477 main(int argc, char ** argv)
1478 {
1479  gnc_numeric a = gnc_numeric_create(1, 3);
1480  gnc_numeric b = gnc_numeric_create(1, 4);
1481  gnc_numeric c;
1482 
1483  gnc_numeric err;
1484 
1485 
1486  printf("multiply (EXACT): %s * %s = %s\n",
1487  gnc_numeric_print(a), gnc_numeric_print(b),
1488  gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT)));
1489 
1490  printf("multiply (REDUCE): %s * %s = %s\n",
1491  gnc_numeric_print(a), gnc_numeric_print(b),
1492  gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE)));
1493 
1494 
1495  return 0;
1496 }
1497 #endif
1498 
1499 
1500 std::ostream&
1501 operator<<(std::ostream& s, GncNumeric n)
1502 {
1503  using boost::locale::conv::utf_to_utf;
1504  std::basic_ostringstream<wchar_t> ss;
1505  ss.imbue(s.getloc());
1506  ss << n;
1507  s << utf_to_utf<char>(ss.str());
1508  return s;
1509 }
1510 
1512 {
1513  switch (error_code)
1514  {
1515  case GNC_ERROR_OK:
1516  return "GNC_ERROR_OK";
1517  case GNC_ERROR_ARG:
1518  return "GNC_ERROR_ARG";
1519  case GNC_ERROR_OVERFLOW:
1520  return "GNC_ERROR_OVERFLOW";
1521  case GNC_ERROR_DENOM_DIFF:
1522  return "GNC_ERROR_DENOM_DIFF";
1523  case GNC_ERROR_REMAINDER:
1524  return "GNC_ERROR_REMAINDER";
1525  default:
1526  return "<unknown>";
1527  }
1528 }
1529 
1530 /* ======================== END OF FILE =================== */
GNC_HOW_RND_NEVER was specified, but the result could not be converted to the desired denominator wit...
Definition: gnc-numeric.h:232
Never round at all, and signal an error if there is a fractional result in a computation.
Definition: gnc-numeric.h:177
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
bool isBig() const noexcept
Definition: gnc-int128.cpp:253
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
GncInt128 denom() const noexcept
Denominator accessor.
gnc_numeric double_to_gnc_numeric(double n, gint64 denom, gint how)
Convert a floating-point number to a gnc_numeric.
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
GncRational reduce() const
Return an equivalent fraction with all common factors between the numerator and the denominator remov...
GncNumeric operator-() const noexcept
GNCNumericErrorCode
Error codes.
Definition: gnc-numeric.h:221
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a+b.
gboolean gnc_numeric_to_decimal(gnc_numeric *a, guint8 *max_decimal_places)
Attempt to convert the denominator to an exact power of ten without rounding.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
The primary numeric class for representing amounts and values.
Definition: gnc-numeric.hpp:60
Intermediate result overflow.
Definition: gnc-numeric.h:225
Use any denominator which gives an exactly correct ratio of numerator to denominator.
Definition: gnc-numeric.h:188
std::string to_string() const noexcept
Return a string representation of the GncNumeric.
gint gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b.
gchar * gnc_numeric_to_string(gnc_numeric n)
Convert to string.
GncNumeric abs() const noexcept
GncNumeric reduce() const noexcept
Return an equivalent fraction with all common factors between the numerator and the denominator remov...
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
gnc_numeric gnc_numeric_reduce(gnc_numeric n)
Return input after reducing it by Greater Common Factor (GCF) elimination.
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
gdouble gnc_numeric_to_double(gnc_numeric n)
Convert numeric to floating-point value.
gnc_numeric gnc_numeric_invert(gnc_numeric num)
Invert a gnc_numeric.
gnc_numeric gnc_numeric_convert(gnc_numeric n, gint64 denom, gint how)
Change the denominator of a gnc_numeric value to the specified denominator under standard arguments &#39;...
Find the least common multiple of the arguments&#39; denominators and use that as the denominator of the ...
Definition: gnc-numeric.h:200
Reduce the result value by common factor elimination, using the smallest possible value for the denom...
Definition: gnc-numeric.h:195
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
const char * gnc_numeric_errorCode_to_string(GNCNumericErrorCode error_code)
Returns a string representation of the given GNCNumericErrorCode.
GncNumeric to_decimal(unsigned int max_places=17) const
Convert the numeric to have a power-of-10 denominator if possible without rounding.
gnc_numeric gnc_numeric_error(GNCNumericErrorCode error_code)
Create a gnc_numeric object that signals the error condition noted by error_code, rather than a numbe...
bool isNan() const noexcept
Definition: gnc-int128.cpp:265
Argument is not a valid number.
Definition: gnc-numeric.h:224
gnc_numeric gnc_numeric_abs(gnc_numeric a)
Returns a newly created gnc_numeric that is the absolute value of the given gnc_numeric value...
Rational number class using GncInt128 for the numerator and denominator.
gnc_numeric gnc_numeric_div(gnc_numeric x, gnc_numeric y, gint64 denom, gint how)
Division.
GncRational round_to_numeric() const
Round to fit an int64_t, finding the closest possible approximation.
gboolean gnc_numeric_eq(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b are exactly the same (have the same numerator and ...
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a-b.
GncNumeric()
Default constructor provides the zero value.
Definition: gnc-numeric.hpp:66
GncInt128 num() const noexcept
Numerator accessor.
GNC_HOW_DENOM_FIXED was specified, but argument denominators differed.
Definition: gnc-numeric.h:228
gnc_numeric gnc_numeric_from_string(const gchar *str)
Read a gnc_numeric from str, skipping any leading whitespace.
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
Check for error signal in value.
int64_t num() const noexcept
Accessor for numerator value.
GncNumeric inv() const noexcept
gint gnc_numeric_same(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Equivalence predicate: Convert both a and b to denom using the specified DENOM and method HOW...
No error.
Definition: gnc-numeric.h:223
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:245
#define GNC_NUMERIC_RND_MASK
bitmasks for HOW flags.
Definition: gnc-numeric.h:126
bool isOverflow() const noexcept
Definition: gnc-int128.cpp:259
bool is_decimal() const noexcept
int64_t denom() const noexcept
Accessor for denominator value.