33 #include <boost/regex.hpp> 34 #include <boost/locale/encoding_utf.hpp> 39 #include "gnc-int128.hpp" 42 #include "gnc-numeric.hpp" 43 #include "gnc-rational.hpp" 48 static QofLogModule log_module =
"qof";
50 static const uint8_t max_leg_digits{18};
51 static const int64_t pten[] = { 1, 10, 100, 1000, 10000, 100000, 1000000,
52 10000000, 100000000, 1000000000,
53 INT64_C(10000000000), INT64_C(100000000000),
54 INT64_C(1000000000000), INT64_C(10000000000000),
55 INT64_C(100000000000000),
56 INT64_C(1000000000000000),
57 INT64_C(10000000000000000),
58 INT64_C(100000000000000000),
59 INT64_C(1000000000000000000)};
60 #define POWTEN_OVERFLOW -5 63 powten (
unsigned int exp)
65 if (exp > max_leg_digits)
74 throw std::underflow_error(
"Operation resulted in NaN.");
76 throw std::overflow_error(
"Operation overflowed a 128-bit int.");
82 m_num =
static_cast<int64_t
>(rr.
num());
83 m_den =
static_cast<int64_t
>(rr.
denom());
88 static uint64_t max_leg_value{INT64_C(1000000000000000000)};
89 if (std::isnan(d) || fabs(d) > max_leg_value)
91 std::ostringstream msg;
92 msg <<
"Unable to construct a GncNumeric from " << d <<
".\n";
93 throw std::invalid_argument(msg.str());
95 constexpr
auto max_num =
static_cast<double>(INT64_MAX);
96 auto logval = log10(fabs(d));
100 den_digits = (max_leg_digits + 1) - static_cast<int>(floor(logval));
102 den_digits = max_leg_digits;
103 den = powten(den_digits);
104 auto num_d =
static_cast<double>(den) * d;
105 while (fabs(num_d) > max_num && den_digits > 1)
107 den = powten(--den_digits);
108 num_d =
static_cast<double>(den) * d;
110 auto num =
static_cast<int64_t
>(floor(num_d));
121 using boost::regex_search;
125 static std::pair<int64_t, int64_t>
126 reduce_number_pair(std::pair<GncInt128, GncInt128>num_pair,
127 const std::string& num_str,
bool autoround)
129 auto [n, d] = num_pair;
130 if (!autoround && n.isBig()) {
131 std::ostringstream errmsg;
132 errmsg <<
"Decimal string " << num_str
133 <<
"can't be represented in a GncNumeric without rounding.";
134 throw std::overflow_error(errmsg.str());
136 while (n.isBig() && d > 0) {
142 std::ostringstream errmsg;
143 errmsg <<
"Decimal string " << num_str
144 <<
" can't be represented in a GncNumeric, even after reducing " 147 throw std::overflow_error(errmsg.str());
149 return std::make_pair(static_cast<int64_t>(n), static_cast<int64_t>(d));
152 static std::pair<GncInt128, int64_t>
153 numeric_from_decimal_match(
const std::string& integer,
const std::string& decimal)
155 auto neg = (!integer.empty() && integer[0] ==
'-');
156 GncInt128 high((neg && integer.length() > 1) || (!neg && !integer.empty())
159 GncInt128 low{ decimal.empty() ? 0 : stoll(decimal)};
160 auto exp10 = decimal.length();
161 int64_t d = powten(exp10);
162 GncInt128 n = high * d + (neg ? -low : low);
163 while (exp10 > max_leg_digits) {
167 n = n / powten(exp10 - max_leg_digits);
168 exp10 -= max_leg_digits;
170 return std::make_pair(n, d);
173 static std::pair<GncInt128, GncInt128>
174 numeric_from_scientific_match(smatch &m)
176 int exp{m[4].matched ? stoi(m[4].str()) : 0};
177 auto neg_exp{exp < 0};
178 exp = neg_exp ? -exp : exp;
179 if (exp >= max_leg_digits)
181 std::ostringstream errmsg;
182 errmsg <<
"Exponent " << m[3].str() <<
" in match " << m[0].str()
183 <<
" exceeds range that GnuCash can parse.";
184 throw std::overflow_error(errmsg.str());
188 auto mult = powten(exp);
192 denom = neg_exp ? mult : 1;
193 num = neg_exp ? stoll(m[1].str()) : mult * stoll(m[1].str());
197 auto [d_num, d_denom] = numeric_from_decimal_match(m[2].str(), m[3].str());
199 if (neg_exp || d_denom > mult)
202 denom = neg_exp ? d_denom * mult : d_denom / mult;
206 num = d_num * mult / d_denom;
210 return std::make_pair(num, denom);
213 static std::optional<gnc_numeric>
214 fast_numeral_rational (
const char* str)
222 auto end_ptr{(
const char*)memchr (str,
'\0', 48)};
226 int64_t num, denom{};
227 auto result = std::from_chars (str, end_ptr, num);
228 if (result.ec != std::errc())
231 if (result.ptr == end_ptr)
232 return gnc_numeric_create (num, 1);
234 if (*result.ptr !=
'/')
237 result = std::from_chars (result.ptr + 1, end_ptr, denom);
238 if (result.ec != std::errc() || result.ptr != end_ptr || denom <= 0)
241 return gnc_numeric_create (num, denom);
245 static const std::string maybe_sign (
"(-?)");
246 static const std::string opt_signed_int(
"(-?[0-9]*)");
247 static const std::string unsigned_int(
"([0-9]+)");
248 static const std::string hex_frag(
"(0[xX][A-Fa-f0-9]+)");
249 static const std::string slash(
"[ \\t]*/[ \\t]*");
250 static const std::string whitespace(
"[ \\t]+");
255 static const regex numeral(opt_signed_int);
256 static const regex hex(hex_frag);
257 static const regex numeral_rational(opt_signed_int + slash + unsigned_int);
258 static const regex integer_and_fraction(maybe_sign + unsigned_int + whitespace + unsigned_int + slash + unsigned_int);
259 static const regex hex_rational(hex_frag + slash + hex_frag);
260 static const regex hex_over_num(hex_frag + slash + unsigned_int);
261 static const regex num_over_hex(opt_signed_int + slash + hex_frag);
262 static const regex decimal(opt_signed_int +
"[.,]" + unsigned_int);
263 static const regex scientific(
"(?:(-?[0-9]+[.,]?)|(-?[0-9]*)[.,]([0-9]+))[Ee](-?[0-9]+)");
264 static const regex has_hex_prefix(
".*0[xX]$");
271 throw std::invalid_argument(
272 "Can't construct a GncNumeric from an empty string.");
273 if (
auto res = fast_numeral_rational (str.c_str()))
279 if (regex_search(str, m, hex_rational))
282 stoll(m[2].str(),
nullptr, 16));
288 if (regex_search(str, m, hex_over_num))
290 GncNumeric n(stoll(m[1].str(),
nullptr, 16), stoll(m[2].str()));
295 if (regex_search(str, m, num_over_hex))
297 GncNumeric n(stoll(m[1].str()), stoll(m[2].str(),
nullptr, 16));
302 if (regex_search(str, m, integer_and_fraction))
304 GncNumeric n(stoll(m[3].str()), stoll(m[4].str()));
305 n += stoll(m[2].str());
306 m_num = m[1].str().empty() ? n.
num() : -n.
num();
310 if (regex_search(str, m, numeral_rational))
312 GncNumeric n(stoll(m[1].str()), stoll(m[2].str()));
317 if (regex_search(str, m, scientific) && ! regex_match(m.prefix().str(), x, has_hex_prefix))
320 reduce_number_pair(numeric_from_scientific_match(m),
326 if (regex_search(str, m, decimal))
328 std::string integer{m[1].matched ? m[1].str() :
""};
329 std::string decimal{m[2].matched ? m[2].str() :
""};
331 reduce_number_pair(numeric_from_decimal_match(integer, decimal),
337 if (regex_search(str, m, hex))
339 GncNumeric n(stoll(m[1].str(),
nullptr, 16), INT64_C(1));
344 if (regex_search(str, m, numeral))
351 std::ostringstream errmsg;
352 errmsg <<
"String " << str <<
" contains no recognizable numeric value.";
353 throw std::invalid_argument(errmsg.str());
356 GncNumeric::operator gnc_numeric() const noexcept
358 return {m_num, m_den};
361 GncNumeric::operator double() const noexcept
363 return static_cast<double>(m_num) / static_cast<double>(m_den);
398 GncNumeric::round_param
399 GncNumeric::prepare_conversion(int64_t new_denom)
const 402 return {m_num, m_den, 0};
404 auto red_conv = conversion.reduce();
406 auto new_num = old_num * red_conv.num();
407 auto rem = new_num % red_conv.denom();
408 new_num /= red_conv.denom();
413 rr = rr.convert<RoundType::truncate>(new_denom);
414 return {
static_cast<int64_t
>(rr.num()), new_denom, 0};
416 return {
static_cast<int64_t
>(new_num),
417 static_cast<int64_t>(red_conv.denom()), static_cast<int64_t>(rem)};
421 GncNumeric::sigfigs_denom(
unsigned figs)
const noexcept
426 int64_t num_abs{std::abs(m_num)};
427 bool not_frac = num_abs > m_den;
428 int64_t val{ not_frac ? num_abs / m_den : m_den / num_abs };
436 powten(digits < figs ? figs - digits - 1 : 0) :
437 powten(figs + digits);
443 std::ostringstream out;
451 for (
unsigned pwr = 0; pwr < max_leg_digits && m_den >= pten[pwr]; ++pwr)
453 if (m_den == pten[pwr])
455 if (m_den % pten[pwr])
464 if (max_places > max_leg_digits)
465 max_places = max_leg_digits;
472 if (m_num == 0 || m_den < powten(max_places))
475 auto excess = m_den / powten(max_places);
478 std::ostringstream msg;
479 msg <<
"GncNumeric " << *
this 480 <<
" could not be represented in " << max_places
481 <<
" decimal places without rounding.\n";
482 throw std::range_error(msg.str());
484 return GncNumeric(m_num / excess, powten(max_places));
487 rr = rr.
convert<RoundType::never>(powten(max_places));
490 for (; pwr <= max_places && !(rr.
denom() % powten(pwr)); ++pwr);
491 auto reduce_to = powten(pwr);
493 if (rr_den % reduce_to)
495 auto factor(reduce_to / rr.
denom());
499 while (!rr_num.isZero() && rr_num > 9 && rr_den > 9 && rr_num % 10 == 0)
509 return {
static_cast<int64_t
>(rr_num), static_cast<int64_t>(rr_den)};
511 catch (
const std::invalid_argument& err)
513 std::ostringstream msg;
514 msg <<
"GncNumeric " << *
this 515 <<
" could not be represented as a decimal without rounding.\n";
516 throw std::range_error(msg.str());
518 catch (
const std::overflow_error& err)
520 std::ostringstream msg;
521 msg <<
"GncNumeric " << *
this 522 <<
" overflows when attempting to convert it to decimal.\n";
523 throw std::range_error(msg.str());
525 catch (
const std::underflow_error& err)
527 std::ostringstream msg;
528 msg <<
"GncNumeric " << *
this 529 <<
" underflows when attempting to convert it to decimal.\n";
530 throw std::range_error(msg.str());
561 if (m_den == b.
denom())
563 auto b_num = b.
num();
564 return m_num < b_num ? -1 : b_num < m_num ? 1 : 0;
591 if (a.num() == 0 || b.
num() == 0)
610 throw std::underflow_error(
"Attempt to divide by zero.");
617 template <
typename T,
typename I> T
618 convert(T num, I new_denom,
int how)
621 unsigned int figs = GNC_HOW_GET_SIGFIGS(how);
623 auto dtype =
static_cast<DenomType
>(how & GNC_NUMERIC_DENOM_MASK);
624 bool sigfigs = dtype == DenomType::sigfigs;
625 if (dtype == DenomType::reduce)
630 case RoundType::floor:
632 return num.template convert_sigfigs<RoundType::floor>(figs);
634 return num.template convert<RoundType::floor>(new_denom);
635 case RoundType::ceiling:
637 return num.template convert_sigfigs<RoundType::ceiling>(figs);
639 return num.template convert<RoundType::ceiling>(new_denom);
640 case RoundType::truncate:
642 return num.template convert_sigfigs<RoundType::truncate>(figs);
644 return num.template convert<RoundType::truncate>(new_denom);
645 case RoundType::promote:
647 return num.template convert_sigfigs<RoundType::promote>(figs);
649 return num.template convert<RoundType::promote>(new_denom);
650 case RoundType::half_down:
652 return num.template convert_sigfigs<RoundType::half_down>(figs);
654 return num.template convert<RoundType::half_down>(new_denom);
655 case RoundType::half_up:
657 return num.template convert_sigfigs<RoundType::half_up>(figs);
659 return num.template convert<RoundType::half_up>(new_denom);
660 case RoundType::bankers:
662 return num.template convert_sigfigs<RoundType::bankers>(figs);
664 return num.template convert<RoundType::bankers>(new_denom);
665 case RoundType::never:
667 return num.template convert_sigfigs<RoundType::never>(figs);
669 return num.template convert<RoundType::never>(new_denom);
677 return num.template convert_sigfigs<RoundType::truncate>(figs);
679 return num.template convert<RoundType::truncate>(new_denom);
691 if (G_LIKELY(in.denom != 0))
697 if ((0 < in.num) || (-4 > in.num))
723 if ((a.num == 0) && (a.denom != 0))
747 if ((a.num < 0) && (a.denom != 0))
771 if ((a.num > 0) && (a.denom != 0))
796 if (a.denom == b.denom)
798 if (a.num == b.num)
return 0;
799 if (a.num > b.num)
return 1;
816 return ((a.num == b.num) && (a.denom == b.denom));
855 gnc_numeric aconv, bconv;
864 denom_lcd(gnc_numeric a, gnc_numeric b, int64_t denom,
int how)
870 denom =
static_cast<int64_t
>(ad.lcm(bd));
881 gint64 denom, gint how)
889 denom = denom_lcd(a, b, denom, how);
894 return static_cast<gnc_numeric
>(convert(sum, denom, how));
900 return static_cast<gnc_numeric
>(sum.round_to_numeric());
901 sum = convert(sum, denom, how);
902 if (sum.is_big() || !sum.valid())
904 return static_cast<gnc_numeric
>(sum);
906 catch (
const std::overflow_error& err)
908 PWARN(
"%s", err.what());
911 catch (
const std::invalid_argument& err)
913 PWARN(
"%s", err.what());
916 catch (
const std::underflow_error& err)
918 PWARN(
"%s", err.what());
921 catch (
const std::domain_error& err)
923 PWARN(
"%s", err.what());
934 gint64 denom, gint how)
942 denom = denom_lcd(a, b, denom, how);
947 return static_cast<gnc_numeric
>(convert(sum, denom, how));
953 return static_cast<gnc_numeric
>(sum.round_to_numeric());
954 sum = convert(sum, denom, how);
955 if (sum.is_big() || !sum.valid())
957 return static_cast<gnc_numeric
>(sum);
959 catch (
const std::overflow_error& err)
961 PWARN(
"%s", err.what());
964 catch (
const std::invalid_argument& err)
966 PWARN(
"%s", err.what());
969 catch (
const std::underflow_error& err)
971 PWARN(
"%s", err.what());
974 catch (
const std::domain_error& err)
976 PWARN(
"%s", err.what());
987 gint64 denom, gint how)
996 denom = denom_lcd(a, b, denom, how);
1000 auto prod = an * bn;
1001 return static_cast<gnc_numeric
>(convert(prod, denom, how));
1004 auto prod = ar * br;
1007 return static_cast<gnc_numeric
>(prod.round_to_numeric());
1008 prod = convert(prod, denom, how);
1009 if (prod.is_big() || !prod.valid())
1011 return static_cast<gnc_numeric
>(prod);
1013 catch (
const std::overflow_error& err)
1015 PWARN(
"%s", err.what());
1018 catch (
const std::invalid_argument& err)
1020 PWARN(
"%s", err.what());
1023 catch (
const std::underflow_error& err)
1025 PWARN(
"%s", err.what());
1028 catch (
const std::domain_error& err)
1030 PWARN(
"%s", err.what());
1042 gint64 denom, gint how)
1050 denom = denom_lcd(a, b, denom, how);
1054 auto quot = an / bn;
1055 return static_cast<gnc_numeric
>(convert(quot, denom, how));
1058 auto quot = ar / br;
1061 return static_cast<gnc_numeric
>(quot.round_to_numeric());
1062 quot =
static_cast<gnc_numeric
>(convert(quot, denom, how));
1063 if (quot.is_big() || !quot.valid())
1065 return static_cast<gnc_numeric
>(quot);
1067 catch (
const std::overflow_error& err)
1069 PWARN(
"%s", err.what());
1072 catch (
const std::invalid_argument& err)
1074 PWARN(
"%s", err.what());
1077 catch (
const std::underflow_error& err)
1079 PWARN(
"%s", err.what());
1082 catch (
const std::domain_error& err)
1084 PWARN(
"%s", err.what());
1101 return gnc_numeric_create(- a.num, a.denom);
1116 return gnc_numeric_create(ABS(a.num), a.denom);
1133 catch (
const std::invalid_argument& err)
1137 catch (
const std::overflow_error& err)
1141 catch (
const std::underflow_error& err)
1145 catch (
const std::domain_error& err)
1171 return static_cast<gnc_numeric
>(an.
reduce());
1173 catch (
const std::overflow_error& err)
1175 PWARN(
"%s", err.what());
1178 catch (
const std::invalid_argument& err)
1180 PWARN(
"%s", err.what());
1183 catch (
const std::underflow_error& err)
1185 PWARN(
"%s", err.what());
1188 catch (
const std::domain_error& err)
1190 PWARN(
"%s", err.what());
1208 int max_places = max_decimal_places == NULL ? max_leg_digits :
1209 *max_decimal_places;
1210 if (a->num == 0)
return TRUE;
1215 *a =
static_cast<gnc_numeric
>(bn);
1218 catch (
const std::exception& err)
1220 PINFO (
"%s", err.what());
1230 return gnc_numeric_zero();
1235 catch (
const std::overflow_error& err)
1237 PWARN(
"%s", err.what());
1240 catch (
const std::invalid_argument& err)
1242 PWARN(
"%s", err.what());
1245 catch (
const std::underflow_error& err)
1247 PWARN(
"%s", err.what());
1250 catch (
const std::domain_error& err)
1252 PWARN(
"%s", err.what());
1270 return convert(an, denom, how);
1272 catch (
const std::overflow_error& err)
1274 PWARN(
"%s", err.what());
1277 catch (
const std::invalid_argument& err)
1279 PWARN(
"%s", err.what());
1282 catch (
const std::underflow_error& err)
1284 PWARN(
"%s", err.what());
1287 catch (
const std::domain_error& err)
1289 PWARN(
"%s", err.what());
1303 return (
double)in.num / (double)in.denom;
1307 return (
double)(in.num * -in.denom);
1318 return gnc_numeric_create(error_code, 0LL);
1331 int64_t tmpnum = n.num;
1332 int64_t tmpdenom = n.denom;
1334 result = g_strdup_printf(
"%" PRId64
"/%" PRId64, tmpnum, tmpdenom);
1342 static char buff[1000];
1343 static char *p = buff;
1344 static const size_t size = 50;
1345 int64_t tmpnum = n.num;
1346 int64_t tmpdenom = n.denom;
1349 if ((
size_t)(p - buff) > (
sizeof(buff) - size))
1352 snprintf(p, size,
"%" PRId64
"/%" PRId64, tmpnum, tmpdenom);
1366 if (
auto res = fast_numeral_rational (str))
1373 catch (
const std::exception& err)
1375 PWARN(
"%s", err.what());
1384 gnc_numeric_boxed_copy_func( gnc_numeric *in_gnc_numeric )
1386 if (!in_gnc_numeric)
1390 auto newvalue =
static_cast<gnc_numeric*
>(g_malloc (
sizeof (gnc_numeric)));
1391 *newvalue = *in_gnc_numeric;
1397 gnc_numeric_boxed_free_func( gnc_numeric *in_gnc_numeric )
1399 g_free( in_gnc_numeric );
1402 G_DEFINE_BOXED_TYPE (gnc_numeric, gnc_numeric, gnc_numeric_boxed_copy_func, gnc_numeric_boxed_free_func)
1407 #ifdef _GNC_NUMERIC_TEST 1410 gnc_numeric_print(gnc_numeric in)
1415 retval = g_strdup_printf(
"<ERROR> [%" G_GINT64_FORMAT
" / %" G_GINT64_FORMAT
"]",
1421 retval = g_strdup_printf(
"[%" G_GINT64_FORMAT
" / %" G_GINT64_FORMAT
"]",
1429 main(
int argc,
char ** argv)
1431 gnc_numeric a = gnc_numeric_create(1, 3);
1432 gnc_numeric b = gnc_numeric_create(1, 4);
1438 printf(
"multiply (EXACT): %s * %s = %s\n",
1439 gnc_numeric_print(a), gnc_numeric_print(b),
1442 printf(
"multiply (REDUCE): %s * %s = %s\n",
1443 gnc_numeric_print(a), gnc_numeric_print(b),
1455 using boost::locale::conv::utf_to_utf;
1456 std::basic_ostringstream<wchar_t> ss;
1457 ss.imbue(s.getloc());
1459 s << utf_to_utf<char>(ss.str());
1468 return "GNC_ERROR_OK";
1470 return "GNC_ERROR_ARG";
1472 return "GNC_ERROR_OVERFLOW";
1474 return "GNC_ERROR_DENOM_DIFF";
1476 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 in, 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.
GncRational convert(GncInt128 new_denom) const
Convert a GncRational to use a new denominator.
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b.
gchar * gnc_numeric_to_string(gnc_numeric n)
Convert to string.
GncNumeric abs() const noexcept
GncNumeric reduce() const noexcept
Return an equivalent fraction with all common factors between the numerator and the denominator remov...
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
gnc_numeric gnc_numeric_reduce(gnc_numeric in)
Return input after reducing it by Greater Common Factor (GCF) elimination.
#define PWARN(format, args...)
Log a warning.
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 '...
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 a, gnc_numeric b, gint64 denom, gint how)
Division.
GncRational round_to_numeric() const
Round to fit an int64_t, finding the closest possible approximation.
gboolean gnc_numeric_eq(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b are exactly the same (have the same numerator and ...
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a-b.
GncNumeric()
Default constructor provides the zero value.
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 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...
#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.