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"
49static QofLogModule log_module =
"qof";
51static const uint8_t max_leg_digits{18};
52static 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
64powten (
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));
122using boost::u32regex;
123using boost::regex_search;
124using boost::u32regex_search;
128static std::pair<int64_t, int64_t>
129reduce_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));
155static std::pair<GncInt128, int64_t>
156numeric_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);
176static std::pair<GncInt128, GncInt128>
177numeric_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);
216static std::optional<gnc_numeric>
217fast_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());
404GncNumeric::operator gnc_numeric() const noexcept
406 return {m_num, m_den};
409GncNumeric::operator double() const noexcept
411 return static_cast<double>(m_num) /
static_cast<double>(m_den);
446GncNumeric::round_param
447GncNumeric::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)};
469GncNumeric::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);
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.");
665template <
typename T,
typename I> T
666convert(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;
905 aconv = gnc_numeric_convert(a, denom, how);
906 bconv = gnc_numeric_convert(b, denom, how);
912denom_lcd(gnc_numeric a, gnc_numeric b, int64_t denom,
int how)
915 (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD)
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);
1173gnc_numeric_convert(gnc_numeric in, int64_t denom,
int how)
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;
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());
1432gnc_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;
1445gnc_numeric_boxed_free_func( gnc_numeric *in_gnc_numeric )
1447 g_free( in_gnc_numeric );
1450G_DEFINE_BOXED_TYPE (gnc_numeric, gnc_numeric, gnc_numeric_boxed_copy_func, gnc_numeric_boxed_free_func)
1455#ifdef _GNC_NUMERIC_TEST
1458gnc_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
"]",
1477main(
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";
bool isOverflow() const noexcept
bool isBig() const noexcept
bool isNan() const noexcept
The primary numeric class for representing amounts and values.
GncNumeric to_decimal(unsigned int max_places=17) const
Convert the numeric to have a power-of-10 denominator if possible without rounding.
GncNumeric reduce() const noexcept
Return an equivalent fraction with all common factors between the numerator and the denominator remov...
GncNumeric operator-() const noexcept
bool is_decimal() const noexcept
GncNumeric inv() const noexcept
int64_t denom() const noexcept
Accessor for denominator value.
GncNumeric abs() const noexcept
GncNumeric()
Default constructor provides the zero value.
int64_t num() const noexcept
Accessor for numerator value.
std::string to_string() const noexcept
Return a string representation of the GncNumeric.
Rational number class using GncInt128 for the numerator and denominator.
GncInt128 denom() const noexcept
Denominator accessor.
GncInt128 num() const noexcept
Numerator accessor.
GncRational round_to_numeric() const
Round to fit an int64_t, finding the closest possible approximation.
GncRational convert(GncInt128 new_denom) const
Convert a GncRational to use a new denominator.
GncRational reduce() const
Return an equivalent fraction with all common factors between the numerator and the denominator remov...
#define PINFO(format, args...)
Print an informational note.
#define PWARN(format, args...)
Log a warning.
GNCNumericErrorCode
Error codes.
const char * gnc_numeric_errorCode_to_string(GNCNumericErrorCode error_code)
Returns a string representation of the given GNCNumericErrorCode.
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.
double gnc_numeric_to_double(gnc_numeric in)
Convert numeric to floating-point value.
#define GNC_NUMERIC_RND_MASK
bitmasks for HOW flags.
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 ...
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a-b.
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,...
gchar * gnc_numeric_to_string(gnc_numeric n)
Convert to string.
#define GNC_DENOM_AUTO
Values that can be passed as the 'denom' argument.
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_div(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Division.
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...
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.
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.
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value.
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
gnc_numeric gnc_numeric_invert(gnc_numeric num)
Invert a gnc_numeric.
gnc_numeric gnc_numeric_reduce(gnc_numeric in)
Return input after reducing it by Greater Common Factor (GCF) elimination.
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a+b.
@ GNC_ERROR_REMAINDER
GNC_HOW_RND_NEVER was specified, but the result could not be converted to the desired denominator wit...
@ GNC_ERROR_OVERFLOW
Intermediate result overflow.
@ GNC_ERROR_DENOM_DIFF
GNC_HOW_DENOM_FIXED was specified, but argument denominators differed.
@ GNC_ERROR_ARG
Argument is not a valid number.
@ GNC_HOW_RND_NEVER
Never round at all, and signal an error if there is a fractional result in a computation.
@ GNC_HOW_DENOM_EXACT
Use any denominator which gives an exactly correct ratio of numerator to denominator.