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