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