33 #include <boost/regex.hpp> 34 #include <boost/regex/icu.hpp> 35 #include <boost/locale/encoding_utf.hpp> 40 #include "gnc-int128.hpp" 43 #include "gnc-numeric.hpp" 44 #include "gnc-rational.hpp" 49 static QofLogModule log_module =
"qof";
51 static const uint8_t max_leg_digits{18};
52 static const int64_t pten[] = { 1, 10, 100, 1000, 10000, 100000, 1000000,
53 10000000, 100000000, 1000000000,
54 INT64_C(10000000000), INT64_C(100000000000),
55 INT64_C(1000000000000), INT64_C(10000000000000),
56 INT64_C(100000000000000),
57 INT64_C(1000000000000000),
58 INT64_C(10000000000000000),
59 INT64_C(100000000000000000),
60 INT64_C(1000000000000000000)};
61 #define POWTEN_OVERFLOW -5 64 powten (
unsigned int exp)
66 if (exp > max_leg_digits)
75 throw std::underflow_error(
"Operation resulted in NaN.");
77 throw std::overflow_error(
"Operation overflowed a 128-bit int.");
83 m_num =
static_cast<int64_t
>(rr.
num());
84 m_den =
static_cast<int64_t
>(rr.
denom());
89 static uint64_t max_leg_value{INT64_C(1000000000000000000)};
90 if (std::isnan(d) || fabs(d) > max_leg_value)
92 std::ostringstream msg;
93 msg <<
"Unable to construct a GncNumeric from " << d <<
".\n";
94 throw std::invalid_argument(msg.str());
96 constexpr
auto max_num =
static_cast<double>(INT64_MAX);
97 auto logval = log10(fabs(d));
101 den_digits = (max_leg_digits + 1) - static_cast<int>(floor(logval));
103 den_digits = max_leg_digits;
104 den = powten(den_digits);
105 auto num_d =
static_cast<double>(den) * d;
106 while (fabs(num_d) > max_num && den_digits > 1)
108 den = powten(--den_digits);
109 num_d =
static_cast<double>(den) * d;
111 auto num =
static_cast<int64_t
>(floor(num_d));
122 using boost::u32regex;
123 using boost::regex_search;
124 using boost::u32regex_search;
128 static std::pair<int64_t, int64_t>
129 reduce_number_pair(std::pair<GncInt128, GncInt128>num_pair,
130 const std::string& num_str,
bool autoround)
132 auto [n, d] = num_pair;
133 if (!autoround && n.isBig()) {
134 std::ostringstream errmsg;
135 errmsg <<
"Decimal string " << num_str
136 <<
"can't be represented in a GncNumeric without rounding.";
137 throw std::overflow_error(errmsg.str());
139 while (n.isBig() && d > 0) {
145 std::ostringstream errmsg;
146 errmsg <<
"Decimal string " << num_str
147 <<
" can't be represented in a GncNumeric, even after reducing " 150 throw std::overflow_error(errmsg.str());
152 return std::make_pair(static_cast<int64_t>(n), static_cast<int64_t>(d));
155 static std::pair<GncInt128, int64_t>
156 numeric_from_decimal_match(
const std::string& integer,
const std::string& decimal)
158 auto neg = (!integer.empty() && integer[0] ==
'-');
159 GncInt128 high((neg && integer.length() > 1) || (!neg && !integer.empty())
162 GncInt128 low{ decimal.empty() ? 0 : stoll(decimal)};
163 auto exp10 = decimal.length();
164 int64_t d = powten(exp10);
165 GncInt128 n = high * d + (neg ? -low : low);
166 while (exp10 > max_leg_digits) {
170 n = n / powten(exp10 - max_leg_digits);
171 exp10 -= max_leg_digits;
173 return std::make_pair(n, d);
176 static std::pair<GncInt128, GncInt128>
177 numeric_from_scientific_match(smatch &m)
179 int exp{m[4].matched ? stoi(m[4].str()) : 0};
180 auto neg_exp{exp < 0};
181 exp = neg_exp ? -exp : exp;
182 if (exp >= max_leg_digits)
184 std::ostringstream errmsg;
185 errmsg <<
"Exponent " << m[3].str() <<
" in match " << m[0].str()
186 <<
" exceeds range that GnuCash can parse.";
187 throw std::overflow_error(errmsg.str());
191 auto mult = powten(exp);
195 denom = neg_exp ? mult : 1;
196 num = neg_exp ? stoll(m[1].str()) : mult * stoll(m[1].str());
200 auto [d_num, d_denom] = numeric_from_decimal_match(m[2].str(), m[3].str());
202 if (neg_exp || d_denom > mult)
205 denom = neg_exp ? d_denom * mult : d_denom / mult;
209 num = d_num * mult / d_denom;
213 return std::make_pair(num, denom);
216 static std::optional<gnc_numeric>
217 fast_numeral_rational (
const char* str)
225 auto end_ptr{(
const char*)memchr (str,
'\0', 48)};
229 int64_t num, denom{};
230 auto result = std::from_chars (str, end_ptr, num);
231 if (result.ec != std::errc())
234 if (result.ptr == end_ptr)
235 return gnc_numeric_create (num, 1);
237 if (*result.ptr !=
'/')
240 result = std::from_chars (result.ptr + 1, end_ptr, denom);
241 if (result.ec != std::errc() || result.ptr != end_ptr || denom <= 0)
244 return gnc_numeric_create (num, denom);
248 static const std::string begin(
"^[^-.0-9]*");
249 static const std::string end(
"[^0-9]*$");
250 static const std::string begin_group(
"(?:");
251 static const std::string end_group(
")");
252 static const std::string or_op(
"|");
253 static const std::string maybe_sign (
"(-?)");
254 static const std::string opt_signed_int(
"(-?[0-9]*)");
255 static const std::string opt_signed_separated_int(
"(-?[0-9]{1,3})");
256 static const std::string unsigned_int(
"([0-9]+)");
257 static const std::string eu_separated_int(
"(?:[[:space:]'.]([0-9]{3}))?");
258 static const std::string en_separated_int(
"(?:\\,([0-9]{3}))?");
259 static const std::string eu_decimal_part(
"(?:\\,([0-9]+))?");
260 static const std::string en_decimal_part(
"(?:\\.([0-9]+))?");
261 static const std::string hex_frag(
"(0[xX][A-Fa-f0-9]+)");
262 static const std::string slash(
"[ \\t]*/[ \\t]*");
263 static const std::string whitespace(
"[ \\t]+");
264 static const std::string eu_sep_decimal(begin_group + opt_signed_separated_int + eu_separated_int + eu_separated_int + eu_separated_int + eu_separated_int + eu_decimal_part + end_group);
265 static const std::string en_sep_decimal(begin_group + opt_signed_separated_int + en_separated_int + en_separated_int + en_separated_int + en_separated_int + en_decimal_part + end_group);
270 static const regex numeral(begin + opt_signed_int + end);
271 static const regex hex(begin + hex_frag + end);
272 static const regex numeral_rational(begin + opt_signed_int + slash + unsigned_int + end);
273 static const regex integer_and_fraction(begin + maybe_sign + unsigned_int + whitespace + unsigned_int + slash + unsigned_int + end);
274 static const regex hex_rational(begin + hex_frag + slash + hex_frag + end);
275 static const regex hex_over_num(begin + hex_frag + slash + unsigned_int + end);
276 static const regex num_over_hex(begin + opt_signed_int + slash + hex_frag + end);
277 static const regex decimal(begin + opt_signed_int +
"[.,]" + unsigned_int + end);
278 static const u32regex sep_decimal =
279 boost::make_u32regex(begin + begin_group + eu_sep_decimal + or_op + en_sep_decimal + end_group + end);
280 static const regex scientific(
"(?:(-?[0-9]+[.,]?)|(-?[0-9]*)[.,]([0-9]+))[Ee](-?[0-9]+)");
281 static const regex has_hex_prefix(
".*0[xX]$");
288 throw std::invalid_argument(
289 "Can't construct a GncNumeric from an empty string.");
290 if (
auto res = fast_numeral_rational (str.c_str()))
296 if (regex_search(str, m, hex_rational))
299 stoll(m[2].str(),
nullptr, 16));
305 if (regex_search(str, m, hex_over_num))
307 GncNumeric n(stoll(m[1].str(),
nullptr, 16), stoll(m[2].str()));
312 if (regex_search(str, m, num_over_hex))
314 GncNumeric n(stoll(m[1].str()), stoll(m[2].str(),
nullptr, 16));
319 if (regex_search(str, m, integer_and_fraction))
321 GncNumeric n(stoll(m[3].str()), stoll(m[4].str()));
322 n += stoll(m[2].str());
323 m_num = m[1].str().empty() ? n.
num() : -n.
num();
327 if (regex_search(str, m, numeral_rational))
329 GncNumeric n(stoll(m[1].str()), stoll(m[2].str()));
334 if (regex_search(str, m, scientific) && ! regex_match(m.prefix().str(), x, has_hex_prefix))
337 reduce_number_pair(numeric_from_scientific_match(m),
343 if (regex_search(str, m, decimal))
345 std::string integer{m[1].matched ? m[1].str() :
""};
346 std::string decimal{m[2].matched ? m[2].str() :
""};
347 auto [
num,
denom] = reduce_number_pair(numeric_from_decimal_match(integer, decimal), str, autoround);
352 if (u32regex_search(str, m, sep_decimal))
364 std::string integer(
""), decimal(
"");
365 for (
auto i{1}; i < 6; ++i)
367 integer += m[i].str();
369 decimal += m[6].str();
370 if (integer.empty() && decimal.empty())
372 for (
auto i{7}; i <12; ++i)
374 integer += m[i].str();
376 decimal += m[12].str();
379 reduce_number_pair(numeric_from_decimal_match(integer, decimal),
385 if (regex_search(str, m, hex))
387 GncNumeric n(stoll(m[1].str(),
nullptr, 16), INT64_C(1));
392 if (regex_search(str, m, numeral))
399 std::ostringstream errmsg;
400 errmsg <<
"String " << str <<
" contains no recognizable numeric value.";
401 throw std::invalid_argument(errmsg.str());
404 GncNumeric::operator gnc_numeric() const noexcept
406 return {m_num, m_den};
409 GncNumeric::operator double() const noexcept
411 return static_cast<double>(m_num) / static_cast<double>(m_den);
446 GncNumeric::round_param
447 GncNumeric::prepare_conversion(int64_t new_denom)
const 450 return {m_num, m_den, 0};
452 auto red_conv = conversion.reduce();
454 auto new_num = old_num * red_conv.num();
455 auto rem = new_num % red_conv.denom();
456 new_num /= red_conv.denom();
461 rr = rr.convert<RoundType::truncate>(new_denom);
462 return {
static_cast<int64_t
>(rr.num()), new_denom, 0};
464 return {
static_cast<int64_t
>(new_num),
465 static_cast<int64_t>(red_conv.denom()), static_cast<int64_t>(rem)};
469 GncNumeric::sigfigs_denom(
unsigned figs)
const noexcept
474 int64_t num_abs{std::abs(m_num)};
475 bool not_frac = num_abs > m_den;
476 int64_t val{ not_frac ? num_abs / m_den : m_den / num_abs };
484 powten(digits < figs ? figs - digits - 1 : 0) :
485 powten(figs + digits);
491 std::ostringstream out;
499 for (
unsigned pwr = 0; pwr < max_leg_digits && m_den >= pten[pwr]; ++pwr)
501 if (m_den == pten[pwr])
503 if (m_den % pten[pwr])
512 if (max_places > max_leg_digits)
513 max_places = max_leg_digits;
520 if (m_num == 0 || m_den < powten(max_places))
523 auto excess = m_den / powten(max_places);
526 std::ostringstream msg;
527 msg <<
"GncNumeric " << *
this 528 <<
" could not be represented in " << max_places
529 <<
" decimal places without rounding.\n";
530 throw std::range_error(msg.str());
532 return GncNumeric(m_num / excess, powten(max_places));
535 rr = rr.convert<RoundType::never>(powten(max_places));
538 for (; pwr <= max_places && !(rr.denom() % powten(pwr)); ++pwr);
539 auto reduce_to = powten(pwr);
540 GncInt128 rr_num(rr.num()), rr_den(rr.denom());
541 if (rr_den % reduce_to)
543 auto factor(reduce_to / rr.denom());
547 while (!rr_num.isZero() && rr_num > 9 && rr_den > 9 && rr_num % 10 == 0)
557 return {
static_cast<int64_t
>(rr_num), static_cast<int64_t>(rr_den)};
559 catch (
const std::invalid_argument& err)
561 std::ostringstream msg;
562 msg <<
"GncNumeric " << *
this 563 <<
" could not be represented as a decimal without rounding.\n";
564 throw std::range_error(msg.str());
566 catch (
const std::overflow_error& err)
568 std::ostringstream msg;
569 msg <<
"GncNumeric " << *
this 570 <<
" overflows when attempting to convert it to decimal.\n";
571 throw std::range_error(msg.str());
573 catch (
const std::underflow_error& err)
575 std::ostringstream msg;
576 msg <<
"GncNumeric " << *
this 577 <<
" underflows when attempting to convert it to decimal.\n";
578 throw std::range_error(msg.str());
609 if (m_den == b.
denom())
611 auto b_num = b.
num();
612 return m_num < b_num ? -1 : b_num < m_num ? 1 : 0;
639 if (a.num() == 0 || b.
num() == 0)
658 throw std::underflow_error(
"Attempt to divide by zero.");
665 template <
typename T,
typename I> T
666 convert(T num, I new_denom,
int how)
669 unsigned int figs = GNC_HOW_GET_SIGFIGS(how);
671 auto dtype =
static_cast<DenomType
>(how & GNC_NUMERIC_DENOM_MASK);
672 bool sigfigs = dtype == DenomType::sigfigs;
673 if (dtype == DenomType::reduce)
678 case RoundType::floor:
680 return num.template convert_sigfigs<RoundType::floor>(figs);
682 return num.template convert<RoundType::floor>(new_denom);
683 case RoundType::ceiling:
685 return num.template convert_sigfigs<RoundType::ceiling>(figs);
687 return num.template convert<RoundType::ceiling>(new_denom);
688 case RoundType::truncate:
690 return num.template convert_sigfigs<RoundType::truncate>(figs);
692 return num.template convert<RoundType::truncate>(new_denom);
693 case RoundType::promote:
695 return num.template convert_sigfigs<RoundType::promote>(figs);
697 return num.template convert<RoundType::promote>(new_denom);
698 case RoundType::half_down:
700 return num.template convert_sigfigs<RoundType::half_down>(figs);
702 return num.template convert<RoundType::half_down>(new_denom);
703 case RoundType::half_up:
705 return num.template convert_sigfigs<RoundType::half_up>(figs);
707 return num.template convert<RoundType::half_up>(new_denom);
708 case RoundType::bankers:
710 return num.template convert_sigfigs<RoundType::bankers>(figs);
712 return num.template convert<RoundType::bankers>(new_denom);
713 case RoundType::never:
715 return num.template convert_sigfigs<RoundType::never>(figs);
717 return num.template convert<RoundType::never>(new_denom);
725 return num.template convert_sigfigs<RoundType::truncate>(figs);
727 return num.template convert<RoundType::truncate>(new_denom);
739 if (G_LIKELY(in.denom != 0))
745 if ((0 < in.num) || (-4 > in.num))
771 if ((a.num == 0) && (a.denom != 0))
795 if ((a.num < 0) && (a.denom != 0))
819 if ((a.num > 0) && (a.denom != 0))
844 if (a.denom == b.denom)
846 if (a.num == b.num)
return 0;
847 if (a.num > b.num)
return 1;
864 return ((a.num == b.num) && (a.denom == b.denom));
903 gnc_numeric aconv, bconv;
912 denom_lcd(gnc_numeric a, gnc_numeric b, int64_t denom,
int how)
918 denom =
static_cast<int64_t
>(ad.lcm(bd));
929 gint64 denom, gint how)
937 denom = denom_lcd(a, b, denom, how);
942 return static_cast<gnc_numeric
>(convert(sum, denom, how));
948 return static_cast<gnc_numeric
>(sum.round_to_numeric());
949 sum = convert(sum, denom, how);
950 if (sum.is_big() || !sum.valid())
952 return static_cast<gnc_numeric
>(sum);
954 catch (
const std::overflow_error& err)
956 PWARN(
"%s", err.what());
959 catch (
const std::invalid_argument& err)
961 PWARN(
"%s", err.what());
964 catch (
const std::underflow_error& err)
966 PWARN(
"%s", err.what());
969 catch (
const std::domain_error& err)
971 PWARN(
"%s", err.what());
982 gint64 denom, gint how)
990 denom = denom_lcd(a, b, denom, how);
995 return static_cast<gnc_numeric
>(convert(sum, denom, how));
1001 return static_cast<gnc_numeric
>(sum.round_to_numeric());
1002 sum = convert(sum, denom, how);
1003 if (sum.is_big() || !sum.valid())
1005 return static_cast<gnc_numeric
>(sum);
1007 catch (
const std::overflow_error& err)
1009 PWARN(
"%s", err.what());
1012 catch (
const std::invalid_argument& err)
1014 PWARN(
"%s", err.what());
1017 catch (
const std::underflow_error& err)
1019 PWARN(
"%s", err.what());
1022 catch (
const std::domain_error& err)
1024 PWARN(
"%s", err.what());
1035 gint64 denom, gint how)
1044 denom = denom_lcd(a, b, denom, how);
1048 auto prod = an * bn;
1049 return static_cast<gnc_numeric
>(convert(prod, denom, how));
1052 auto prod = ar * br;
1055 return static_cast<gnc_numeric
>(prod.round_to_numeric());
1056 prod = convert(prod, denom, how);
1057 if (prod.is_big() || !prod.valid())
1059 return static_cast<gnc_numeric
>(prod);
1061 catch (
const std::overflow_error& err)
1063 PWARN(
"%s", err.what());
1066 catch (
const std::invalid_argument& err)
1068 PWARN(
"%s", err.what());
1071 catch (
const std::underflow_error& err)
1073 PWARN(
"%s", err.what());
1076 catch (
const std::domain_error& err)
1078 PWARN(
"%s", err.what());
1090 gint64 denom, gint how)
1098 denom = denom_lcd(a, b, denom, how);
1102 auto quot = an / bn;
1103 return static_cast<gnc_numeric
>(convert(quot, denom, how));
1106 auto quot = ar / br;
1109 return static_cast<gnc_numeric
>(quot.round_to_numeric());
1110 quot =
static_cast<gnc_numeric
>(convert(quot, denom, how));
1111 if (quot.is_big() || !quot.valid())
1113 return static_cast<gnc_numeric
>(quot);
1115 catch (
const std::overflow_error& err)
1117 PWARN(
"%s", err.what());
1120 catch (
const std::invalid_argument& err)
1122 PWARN(
"%s", err.what());
1125 catch (
const std::underflow_error& err)
1127 PWARN(
"%s", err.what());
1130 catch (
const std::domain_error& err)
1132 PWARN(
"%s", err.what());
1149 return gnc_numeric_create(- a.num, a.denom);
1164 return gnc_numeric_create(ABS(a.num), a.denom);
1181 catch (
const std::invalid_argument& err)
1185 catch (
const std::overflow_error& err)
1189 catch (
const std::underflow_error& err)
1193 catch (
const std::domain_error& err)
1219 return static_cast<gnc_numeric
>(an.reduce());
1221 catch (
const std::overflow_error& err)
1223 PWARN(
"%s", err.what());
1226 catch (
const std::invalid_argument& err)
1228 PWARN(
"%s", err.what());
1231 catch (
const std::underflow_error& err)
1233 PWARN(
"%s", err.what());
1236 catch (
const std::domain_error& err)
1238 PWARN(
"%s", err.what());
1256 int max_places = max_decimal_places == NULL ? max_leg_digits :
1257 *max_decimal_places;
1258 if (a->num == 0)
return TRUE;
1262 auto bn = an.to_decimal(max_places);
1263 *a =
static_cast<gnc_numeric
>(bn);
1266 catch (
const std::exception& err)
1268 PINFO (
"%s", err.what());
1278 return gnc_numeric_zero();
1283 catch (
const std::overflow_error& err)
1285 PWARN(
"%s", err.what());
1288 catch (
const std::invalid_argument& err)
1290 PWARN(
"%s", err.what());
1293 catch (
const std::underflow_error& err)
1295 PWARN(
"%s", err.what());
1298 catch (
const std::domain_error& err)
1300 PWARN(
"%s", err.what());
1318 return convert(an, denom, how);
1320 catch (
const std::overflow_error& err)
1322 PWARN(
"%s", err.what());
1325 catch (
const std::invalid_argument& err)
1327 PWARN(
"%s", err.what());
1330 catch (
const std::underflow_error& err)
1332 PWARN(
"%s", err.what());
1335 catch (
const std::domain_error& err)
1337 PWARN(
"%s", err.what());
1351 return (
double)in.num / (double)in.denom;
1355 return (
double)(in.num * -in.denom);
1366 return gnc_numeric_create(error_code, 0LL);
1379 int64_t tmpnum = n.num;
1380 int64_t tmpdenom = n.denom;
1382 result = g_strdup_printf(
"%" PRId64
"/%" PRId64, tmpnum, tmpdenom);
1390 static char buff[1000];
1391 static char *p = buff;
1392 static const size_t size = 50;
1393 int64_t tmpnum = n.num;
1394 int64_t tmpdenom = n.denom;
1397 if ((
size_t)(p - buff) > (
sizeof(buff) - size))
1400 snprintf(p, size,
"%" PRId64
"/%" PRId64, tmpnum, tmpdenom);
1414 if (
auto res = fast_numeral_rational (str))
1421 catch (
const std::exception& err)
1423 PWARN(
"%s", err.what());
1432 gnc_numeric_boxed_copy_func( gnc_numeric *in_gnc_numeric )
1434 if (!in_gnc_numeric)
1438 auto newvalue =
static_cast<gnc_numeric*
>(g_malloc (
sizeof (gnc_numeric)));
1439 *newvalue = *in_gnc_numeric;
1445 gnc_numeric_boxed_free_func( gnc_numeric *in_gnc_numeric )
1447 g_free( in_gnc_numeric );
1450 G_DEFINE_BOXED_TYPE (gnc_numeric, gnc_numeric, gnc_numeric_boxed_copy_func, gnc_numeric_boxed_free_func)
1455 #ifdef _GNC_NUMERIC_TEST 1458 gnc_numeric_print(gnc_numeric in)
1463 retval = g_strdup_printf(
"<ERROR> [%" G_GINT64_FORMAT
" / %" G_GINT64_FORMAT
"]",
1469 retval = g_strdup_printf(
"[%" G_GINT64_FORMAT
" / %" G_GINT64_FORMAT
"]",
1477 main(
int argc,
char ** argv)
1479 gnc_numeric a = gnc_numeric_create(1, 3);
1480 gnc_numeric b = gnc_numeric_create(1, 4);
1486 printf(
"multiply (EXACT): %s * %s = %s\n",
1487 gnc_numeric_print(a), gnc_numeric_print(b),
1490 printf(
"multiply (REDUCE): %s * %s = %s\n",
1491 gnc_numeric_print(a), gnc_numeric_print(b),
1503 using boost::locale::conv::utf_to_utf;
1504 std::basic_ostringstream<wchar_t> ss;
1505 ss.imbue(s.getloc());
1507 s << utf_to_utf<char>(ss.str());
1516 return "GNC_ERROR_OK";
1518 return "GNC_ERROR_ARG";
1520 return "GNC_ERROR_OVERFLOW";
1522 return "GNC_ERROR_DENOM_DIFF";
1524 return "GNC_ERROR_REMAINDER";
GNC_HOW_RND_NEVER was specified, but the result could not be converted to the desired denominator wit...
Never round at all, and signal an error if there is a fractional result in a computation.
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
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
GncInt128 denom() const noexcept
Denominator accessor.
gnc_numeric double_to_gnc_numeric(double n, gint64 denom, gint how)
Convert a floating-point number to a gnc_numeric.
#define PINFO(format, args...)
Print an informational note.
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.
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.
Intermediate result overflow.
Use any denominator which gives an exactly correct ratio of numerator to denominator.
std::string to_string() const noexcept
Return a string representation of the GncNumeric.
gint gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b.
gchar * gnc_numeric_to_string(gnc_numeric n)
Convert to string.
GncNumeric abs() const noexcept
GncNumeric reduce() const noexcept
Return an equivalent fraction with all common factors between the numerator and the denominator remov...
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
gnc_numeric gnc_numeric_reduce(gnc_numeric n)
Return input after reducing it by Greater Common Factor (GCF) elimination.
#define PWARN(format, args...)
Log a warning.
gdouble gnc_numeric_to_double(gnc_numeric n)
Convert numeric to floating-point value.
gnc_numeric gnc_numeric_invert(gnc_numeric num)
Invert a gnc_numeric.
gnc_numeric gnc_numeric_convert(gnc_numeric n, gint64 denom, gint how)
Change the denominator of a gnc_numeric value to the specified denominator under standard arguments '...
Find the least common multiple of the arguments' denominators and use that as the denominator of the ...
Reduce the result value by common factor elimination, using the smallest possible value for the denom...
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
Argument is not a valid number.
gnc_numeric gnc_numeric_abs(gnc_numeric a)
Returns a newly created gnc_numeric that is the absolute value of the given gnc_numeric value...
Rational number class using GncInt128 for the numerator and denominator.
gnc_numeric gnc_numeric_div(gnc_numeric x, gnc_numeric y, gint64 denom, gint how)
Division.
GncRational round_to_numeric() const
Round to fit an int64_t, finding the closest possible approximation.
gboolean gnc_numeric_eq(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b are exactly the same (have the same numerator and ...
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a-b.
GncNumeric()
Default constructor provides the zero value.
GncInt128 num() const noexcept
Numerator accessor.
GNC_HOW_DENOM_FIXED was specified, but argument denominators differed.
gnc_numeric gnc_numeric_from_string(const gchar *str)
Read a gnc_numeric from str, skipping any leading whitespace.
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
Check for error signal in value.
int64_t num() const noexcept
Accessor for numerator value.
GncNumeric inv() const noexcept
gint gnc_numeric_same(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Equivalence predicate: Convert both a and b to denom using the specified DENOM and method HOW...
#define GNC_DENOM_AUTO
Values that can be passed as the 'denom' argument.
#define GNC_NUMERIC_RND_MASK
bitmasks for HOW flags.
bool isOverflow() const noexcept
bool is_decimal() const noexcept
int64_t denom() const noexcept
Accessor for denominator value.