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
powten(unsigned int exp)59 powten (unsigned int exp)
60 {
61 if (exp > max_leg_digits)
62 exp = max_leg_digits;
63 return pten[exp];
64 }
65
GncNumeric(GncRational rr)66 GncNumeric::GncNumeric(GncRational rr)
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
GncNumeric(double d)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;
GncNumeric(const std::string & str,bool autoround)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
operator gnc_numeric() const226 GncNumeric::operator gnc_numeric() const noexcept
227 {
228 return {m_num, m_den};
229 }
230
operator double() const231 GncNumeric::operator double() const noexcept
232 {
233 return static_cast<double>(m_num) / static_cast<double>(m_den);
234 }
235
236 GncNumeric
operator -() const237 GncNumeric::operator-() const noexcept
238 {
239 GncNumeric b(*this);
240 b.m_num = - b.m_num;
241 return b;
242 }
243
244 GncNumeric
inv() const245 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
254 GncNumeric
abs() const255 GncNumeric::abs() const noexcept
256 {
257 if (m_num < 0)
258 return -*this;
259 return *this;
260 }
261
262 GncNumeric
reduce() const263 GncNumeric::reduce() const noexcept
264 {
265 return static_cast<GncNumeric>(GncRational(*this).reduce());
266 }
267
268 GncNumeric::round_param
prepare_conversion(int64_t new_denom) const269 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
sigfigs_denom(unsigned figs) const291 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
to_string() const311 GncNumeric::to_string() const noexcept
312 {
313 std::ostringstream out;
314 out << *this;
315 return out.str();
316 }
317
318 bool
is_decimal() const319 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
331 GncNumeric
to_decimal(unsigned int max_places) const332 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
operator +=(GncNumeric b)405 GncNumeric::operator+=(GncNumeric b)
406 {
407 *this = *this + b;
408 }
409
410 void
operator -=(GncNumeric b)411 GncNumeric::operator-=(GncNumeric b)
412 {
413 *this = *this - b;
414 }
415
416 void
operator *=(GncNumeric b)417 GncNumeric::operator*=(GncNumeric b)
418 {
419 *this = *this * b;
420 }
421
422 void
operator /=(GncNumeric b)423 GncNumeric::operator/=(GncNumeric b)
424 {
425 *this = *this / b;
426 }
427
428 int
cmp(GncNumeric b)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
440 GncNumeric
operator +(GncNumeric a,GncNumeric b)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
452 GncNumeric
operator -(GncNumeric a,GncNumeric b)453 operator-(GncNumeric a, GncNumeric b)
454 {
455 return a + (-b);
456 }
457
458 GncNumeric
operator *(GncNumeric a,GncNumeric b)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
471 GncNumeric
operator /(GncNumeric a,GncNumeric b)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 */
558 GNCNumericErrorCode
gnc_numeric_check(gnc_numeric in)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
gnc_numeric_zero_p(gnc_numeric a)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
gnc_numeric_negative_p(gnc_numeric a)609 gnc_numeric_negative_p(gnc_numeric a)
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
gnc_numeric_positive_p(gnc_numeric a)633 gnc_numeric_positive_p(gnc_numeric a)
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
gnc_numeric_compare(gnc_numeric a,gnc_numeric b)659 gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
660 {
661 gint64 aa, bb;
662
663 if (gnc_numeric_check(a) || gnc_numeric_check(b))
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
gnc_numeric_eq(gnc_numeric a,gnc_numeric b)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
gnc_numeric_equal(gnc_numeric a,gnc_numeric b)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
gnc_numeric_same(gnc_numeric a,gnc_numeric b,gint64 denom,gint how)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
denom_lcd(gnc_numeric a,gnc_numeric b,int64_t denom,int how)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
gnc_numeric_add(gnc_numeric a,gnc_numeric b,gint64 denom,gint how)752 gnc_numeric_add(gnc_numeric a, gnc_numeric b,
753 gint64 denom, gint how)
754 {
755 if (gnc_numeric_check(a) || gnc_numeric_check(b))
756 {
757 return gnc_numeric_error(GNC_ERROR_ARG);
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 &&
771 (how & GNC_NUMERIC_RND_MASK) != GNC_HOW_RND_NEVER)
772 return static_cast<gnc_numeric>(sum.round_to_numeric());
773 sum = convert(sum, denom, how);
774 if (sum.is_big() || !sum.valid())
775 return gnc_numeric_error(GNC_ERROR_OVERFLOW);
776 return static_cast<gnc_numeric>(sum);
777 }
778 catch (const std::overflow_error& err)
779 {
780 PWARN("%s", err.what());
781 return gnc_numeric_error(GNC_ERROR_OVERFLOW);
782 }
783 catch (const std::invalid_argument& err)
784 {
785 PWARN("%s", err.what());
786 return gnc_numeric_error(GNC_ERROR_ARG);
787 }
788 catch (const std::underflow_error& err)
789 {
790 PWARN("%s", err.what());
791 return gnc_numeric_error(GNC_ERROR_OVERFLOW);
792 }
793 catch (const std::domain_error& err)
794 {
795 PWARN("%s", err.what());
796 return gnc_numeric_error(GNC_ERROR_REMAINDER);
797 }
798 }
799
800 /* *******************************************************************
801 * gnc_numeric_sub
802 ********************************************************************/
803
804 gnc_numeric
gnc_numeric_sub(gnc_numeric a,gnc_numeric b,gint64 denom,gint how)805 gnc_numeric_sub(gnc_numeric a, gnc_numeric b,
806 gint64 denom, gint how)
807 {
808 gnc_numeric nb;
809 if (gnc_numeric_check(a) || gnc_numeric_check(b))
810 {
811 return gnc_numeric_error(GNC_ERROR_ARG);
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 &&
825 (how & GNC_NUMERIC_RND_MASK) != GNC_HOW_RND_NEVER)
826 return static_cast<gnc_numeric>(sum.round_to_numeric());
827 sum = convert(sum, denom, how);
828 if (sum.is_big() || !sum.valid())
829 return gnc_numeric_error(GNC_ERROR_OVERFLOW);
830 return static_cast<gnc_numeric>(sum);
831 }
832 catch (const std::overflow_error& err)
833 {
834 PWARN("%s", err.what());
835 return gnc_numeric_error(GNC_ERROR_OVERFLOW);
836 }
837 catch (const std::invalid_argument& err)
838 {
839 PWARN("%s", err.what());
840 return gnc_numeric_error(GNC_ERROR_ARG);
841 }
842 catch (const std::underflow_error& err)
843 {
844 PWARN("%s", err.what());
845 return gnc_numeric_error(GNC_ERROR_OVERFLOW);
846 }
847 catch (const std::domain_error& err)
848 {
849 PWARN("%s", err.what());
850 return gnc_numeric_error(GNC_ERROR_REMAINDER);
851 }
852 }
853
854 /* *******************************************************************
855 * gnc_numeric_mul
856 ********************************************************************/
857
858 gnc_numeric
gnc_numeric_mul(gnc_numeric a,gnc_numeric b,gint64 denom,gint how)859 gnc_numeric_mul(gnc_numeric a, gnc_numeric b,
860 gint64 denom, gint how)
861 {
862 if (gnc_numeric_check(a) || gnc_numeric_check(b))
863 {
864 return gnc_numeric_error(GNC_ERROR_ARG);
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 &&
879 (how & GNC_NUMERIC_RND_MASK) != GNC_HOW_RND_NEVER)
880 return static_cast<gnc_numeric>(prod.round_to_numeric());
881 prod = convert(prod, denom, how);
882 if (prod.is_big() || !prod.valid())
883 return gnc_numeric_error(GNC_ERROR_OVERFLOW);
884 return static_cast<gnc_numeric>(prod);
885 }
886 catch (const std::overflow_error& err)
887 {
888 PWARN("%s", err.what());
889 return gnc_numeric_error(GNC_ERROR_OVERFLOW);
890 }
891 catch (const std::invalid_argument& err)
892 {
893 PWARN("%s", err.what());
894 return gnc_numeric_error(GNC_ERROR_ARG);
895 }
896 catch (const std::underflow_error& err)
897 {
898 PWARN("%s", err.what());
899 return gnc_numeric_error(GNC_ERROR_OVERFLOW);
900 }
901 catch (const std::domain_error& err)
902 {
903 PWARN("%s", err.what());
904 return gnc_numeric_error(GNC_ERROR_REMAINDER);
905 }
906 }
907
908
909 /* *******************************************************************
910 * gnc_numeric_div
911 ********************************************************************/
912
913 gnc_numeric
gnc_numeric_div(gnc_numeric a,gnc_numeric b,gint64 denom,gint how)914 gnc_numeric_div(gnc_numeric a, gnc_numeric b,
915 gint64 denom, gint how)
916 {
917 if (gnc_numeric_check(a) || gnc_numeric_check(b))
918 {
919 return gnc_numeric_error(GNC_ERROR_ARG);
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 &&
933 (how & GNC_NUMERIC_RND_MASK) != GNC_HOW_RND_NEVER)
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())
937 return gnc_numeric_error(GNC_ERROR_OVERFLOW);
938 return static_cast<gnc_numeric>(quot);
939 }
940 catch (const std::overflow_error& err)
941 {
942 PWARN("%s", err.what());
943 return gnc_numeric_error(GNC_ERROR_OVERFLOW);
944 }
945 catch (const std::invalid_argument& err)
946 {
947 PWARN("%s", err.what());
948 return gnc_numeric_error(GNC_ERROR_ARG);
949 }
950 catch (const std::underflow_error& err) //Divide by zero
951 {
952 PWARN("%s", err.what());
953 return gnc_numeric_error(GNC_ERROR_OVERFLOW);
954 }
955 catch (const std::domain_error& err)
956 {
957 PWARN("%s", err.what());
958 return gnc_numeric_error(GNC_ERROR_REMAINDER);
959 }
960 }
961
962 /* *******************************************************************
963 * gnc_numeric_neg
964 * negate the argument
965 ********************************************************************/
966
967 gnc_numeric
gnc_numeric_neg(gnc_numeric a)968 gnc_numeric_neg(gnc_numeric a)
969 {
970 if (gnc_numeric_check(a))
971 {
972 return gnc_numeric_error(GNC_ERROR_ARG);
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
gnc_numeric_abs(gnc_numeric a)983 gnc_numeric_abs(gnc_numeric a)
984 {
985 if (gnc_numeric_check(a))
986 {
987 return gnc_numeric_error(GNC_ERROR_ARG);
988 }
989 return gnc_numeric_create(ABS(a.num), a.denom);
990 }
991
992
993 /* *******************************************************************
994 * gnc_numeric_convert
995 ********************************************************************/
996
997 gnc_numeric
gnc_numeric_convert(gnc_numeric in,int64_t denom,int how)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 {
1008 return gnc_numeric_error(GNC_ERROR_OVERFLOW);
1009 }
1010 catch (const std::overflow_error& err)
1011 {
1012 return gnc_numeric_error(GNC_ERROR_OVERFLOW);
1013 }
1014 catch (const std::underflow_error& err)
1015 {
1016 return gnc_numeric_error(GNC_ERROR_OVERFLOW);
1017 }
1018 catch (const std::domain_error& err)
1019 {
1020 return gnc_numeric_error(GNC_ERROR_REMAINDER);
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
gnc_numeric_reduce(gnc_numeric in)1032 gnc_numeric_reduce(gnc_numeric in)
1033 {
1034 if (gnc_numeric_check(in))
1035 {
1036 return gnc_numeric_error(GNC_ERROR_ARG);
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());
1049 return gnc_numeric_error(GNC_ERROR_OVERFLOW);
1050 }
1051 catch (const std::invalid_argument& err)
1052 {
1053 PWARN("%s", err.what());
1054 return gnc_numeric_error(GNC_ERROR_ARG);
1055 }
1056 catch (const std::underflow_error& err)
1057 {
1058 PWARN("%s", err.what());
1059 return gnc_numeric_error(GNC_ERROR_ARG);
1060 }
1061 catch (const std::domain_error& err)
1062 {
1063 PWARN("%s", err.what());
1064 return gnc_numeric_error(GNC_ERROR_REMAINDER);
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
gnc_numeric_to_decimal(gnc_numeric * a,guint8 * max_decimal_places)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
gnc_numeric_invert(gnc_numeric num)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());
1111 return gnc_numeric_error(GNC_ERROR_OVERFLOW);
1112 }
1113 catch (const std::invalid_argument& err)
1114 {
1115 PWARN("%s", err.what());
1116 return gnc_numeric_error(GNC_ERROR_ARG);
1117 }
1118 catch (const std::underflow_error& err)
1119 {
1120 PWARN("%s", err.what());
1121 return gnc_numeric_error(GNC_ERROR_ARG);
1122 }
1123 catch (const std::domain_error& err)
1124 {
1125 PWARN("%s", err.what());
1126 return gnc_numeric_error(GNC_ERROR_REMAINDER);
1127 }
1128 }
1129
1130 /* *******************************************************************
1131 * double_to_gnc_numeric
1132 ********************************************************************/
1133
1134 #ifdef _MSC_VER
1135 # define rint /* */
1136 #endif
1137 gnc_numeric
double_to_gnc_numeric(double in,gint64 denom,gint how)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());
1148 return gnc_numeric_error(GNC_ERROR_OVERFLOW);
1149 }
1150 catch (const std::invalid_argument& err)
1151 {
1152 PWARN("%s", err.what());
1153 return gnc_numeric_error(GNC_ERROR_ARG);
1154 }
1155 catch (const std::underflow_error& err)
1156 {
1157 PWARN("%s", err.what());
1158 return gnc_numeric_error(GNC_ERROR_ARG);
1159 }
1160 catch (const std::domain_error& err)
1161 {
1162 PWARN("%s", err.what());
1163 return gnc_numeric_error(GNC_ERROR_REMAINDER);
1164 }
1165 }
1166
1167 /* *******************************************************************
1168 * gnc_numeric_to_double
1169 ********************************************************************/
1170
1171 double
gnc_numeric_to_double(gnc_numeric in)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
gnc_numeric_error(GNCNumericErrorCode error_code)1189 gnc_numeric_error(GNCNumericErrorCode error_code)
1190 {
1191 return gnc_numeric_create(error_code, 0LL);
1192 }
1193
1194
1195
1196 /* *******************************************************************
1197 * gnc_numeric text IO
1198 ********************************************************************/
1199
1200 gchar *
gnc_numeric_to_string(gnc_numeric n)1201 gnc_numeric_to_string(gnc_numeric n)
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 *
gnc_num_dbg_to_string(gnc_numeric n)1213 gnc_num_dbg_to_string(gnc_numeric n)
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
string_to_gnc_numeric(const gchar * str,gnc_numeric * n)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
gnc_numeric_boxed_copy_func(gpointer in_ptr)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
gnc_numeric_boxed_free_func(gpointer in_gnc_numeric)1262 gnc_numeric_boxed_free_func( gpointer in_gnc_numeric )
1263 {
1264 g_free( in_gnc_numeric );
1265 }
1266
1267 GType
gnc_numeric_get_type(void)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 *
gnc_numeric_print(gnc_numeric in)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
main(int argc,char ** argv)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&
operator <<(std::ostream & s,GncNumeric n)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
gnc_numeric_errorCode_to_string(GNCNumericErrorCode error_code)1341 const char* gnc_numeric_errorCode_to_string(GNCNumericErrorCode error_code)
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 =================== */
1361