mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Reimplement gnc_numeric with QofInt128
And in a more C++ idiom.
This commit is contained in:
parent
ab94094523
commit
33a0c4e968
@ -153,21 +153,21 @@ check_reduce (void)
|
|||||||
check_unary_op (gnc_numeric_eq,
|
check_unary_op (gnc_numeric_eq,
|
||||||
gnc_numeric_create (5011617, 167108327),
|
gnc_numeric_create (5011617, 167108327),
|
||||||
rval,
|
rval,
|
||||||
val, "check_reduce(1) expected %s = %s = reduce(%s)");
|
val, "check_reduce(1) expected %s got %s = reduce(%s)");
|
||||||
|
|
||||||
val = gnc_numeric_create(17474724864LL, 136048896LL);
|
val = gnc_numeric_create(17474724864LL, 136048896LL);
|
||||||
rval = gnc_numeric_reduce (val);
|
rval = gnc_numeric_reduce (val);
|
||||||
check_unary_op (gnc_numeric_eq,
|
check_unary_op (gnc_numeric_eq,
|
||||||
gnc_numeric_create (4 * 17 * 17, 9),
|
gnc_numeric_create (4 * 17 * 17, 9),
|
||||||
rval,
|
rval,
|
||||||
val, "check_reduce(2) expected %s = %s = reduce(%s)");
|
val, "check_reduce(2) expected %s got %s = reduce(%s)");
|
||||||
|
|
||||||
val = gnc_numeric_create(1024LL, 1099511627776LL);
|
val = gnc_numeric_create(1024LL, 1099511627776LL);
|
||||||
rval = gnc_numeric_reduce (val);
|
rval = gnc_numeric_reduce (val);
|
||||||
check_unary_op (gnc_numeric_eq,
|
check_unary_op (gnc_numeric_eq,
|
||||||
gnc_numeric_create (1, 1024 * 1024 * 1024),
|
gnc_numeric_create (1, 1024 * 1024 * 1024),
|
||||||
rval,
|
rval,
|
||||||
val, "check_reduce(3): expected %s = %s = reduce(%s)");
|
val, "check_reduce(3): expected %s got %s = reduce(%s)");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ======================================================= */
|
/* ======================================================= */
|
||||||
@ -235,7 +235,7 @@ check_equality_operator (void)
|
|||||||
bval = gnc_numeric_reduce (val);
|
bval = gnc_numeric_reduce (val);
|
||||||
rval = gnc_numeric_reduce (mval);
|
rval = gnc_numeric_reduce (mval);
|
||||||
check_unary_op (gnc_numeric_eq,
|
check_unary_op (gnc_numeric_eq,
|
||||||
bval, rval, mval, "expected %s = %s = reduce(%s)");
|
bval, rval, mval, "expected %s got %s = reduce(%s)");
|
||||||
|
|
||||||
/* The unreduced versions should be equal */
|
/* The unreduced versions should be equal */
|
||||||
check_unary_op (gnc_numeric_equal,
|
check_unary_op (gnc_numeric_equal,
|
||||||
@ -277,56 +277,56 @@ check_rounding (void)
|
|||||||
check_unary_op (gnc_numeric_eq,
|
check_unary_op (gnc_numeric_eq,
|
||||||
gnc_numeric_create (43, 100),
|
gnc_numeric_create (43, 100),
|
||||||
gnc_numeric_convert (val, 100, GNC_HOW_RND_FLOOR),
|
gnc_numeric_convert (val, 100, GNC_HOW_RND_FLOOR),
|
||||||
val, "expected %s = %s = (%s as 100th's floor)");
|
val, "expected %s got %s = (%s as 100th's floor)");
|
||||||
check_unary_op (gnc_numeric_eq,
|
check_unary_op (gnc_numeric_eq,
|
||||||
gnc_numeric_create (44, 100),
|
gnc_numeric_create (44, 100),
|
||||||
gnc_numeric_convert (val, 100, GNC_HOW_RND_CEIL),
|
gnc_numeric_convert (val, 100, GNC_HOW_RND_CEIL),
|
||||||
val, "expected %s = %s = (%s as 100th's ceiling)");
|
val, "expected %s got %s = (%s as 100th's ceiling)");
|
||||||
check_unary_op (gnc_numeric_eq,
|
check_unary_op (gnc_numeric_eq,
|
||||||
gnc_numeric_create (43, 100),
|
gnc_numeric_create (43, 100),
|
||||||
gnc_numeric_convert (val, 100, GNC_HOW_RND_TRUNC),
|
gnc_numeric_convert (val, 100, GNC_HOW_RND_TRUNC),
|
||||||
val, "expected %s = %s = (%s as 100th's trunc)");
|
val, "expected %s got %s = (%s as 100th's trunc)");
|
||||||
check_unary_op (gnc_numeric_eq,
|
check_unary_op (gnc_numeric_eq,
|
||||||
gnc_numeric_create (44, 100),
|
gnc_numeric_create (44, 100),
|
||||||
gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
|
gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
|
||||||
val, "expected %s = %s = (%s as 100th's round)");
|
val, "expected %s got %s = (%s as 100th's round)");
|
||||||
|
|
||||||
val = gnc_numeric_create(1511, 1000);
|
val = gnc_numeric_create(1511, 1000);
|
||||||
check_unary_op (gnc_numeric_eq,
|
check_unary_op (gnc_numeric_eq,
|
||||||
gnc_numeric_create (151, 100),
|
gnc_numeric_create (151, 100),
|
||||||
gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
|
gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
|
||||||
val, "expected %s = %s = (%s as 100th's round)");
|
val, "expected %s got %s = (%s as 100th's round)");
|
||||||
|
|
||||||
val = gnc_numeric_create(1516, 1000);
|
val = gnc_numeric_create(1516, 1000);
|
||||||
check_unary_op (gnc_numeric_eq,
|
check_unary_op (gnc_numeric_eq,
|
||||||
gnc_numeric_create (152, 100),
|
gnc_numeric_create (152, 100),
|
||||||
gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
|
gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
|
||||||
val, "expected %s = %s = (%s as 100th's round)");
|
val, "expected %s got %s = (%s as 100th's round)");
|
||||||
|
|
||||||
/* Half-values always get rounded to nearest even number */
|
/* Half-values always get rounded to nearest even number */
|
||||||
val = gnc_numeric_create(1515, 1000);
|
val = gnc_numeric_create(1515, 1000);
|
||||||
check_unary_op (gnc_numeric_eq,
|
check_unary_op (gnc_numeric_eq,
|
||||||
gnc_numeric_create (152, 100),
|
gnc_numeric_create (152, 100),
|
||||||
gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
|
gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
|
||||||
val, "expected %s = %s = (%s as 100th's round)");
|
val, "expected %s got %s = (%s as 100th's round)");
|
||||||
|
|
||||||
val = gnc_numeric_create(1525, 1000);
|
val = gnc_numeric_create(1525, 1000);
|
||||||
check_unary_op (gnc_numeric_eq,
|
check_unary_op (gnc_numeric_eq,
|
||||||
gnc_numeric_create (152, 100),
|
gnc_numeric_create (152, 100),
|
||||||
gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
|
gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
|
||||||
val, "expected %s = %s = (%s as 100th's round)");
|
val, "expected %s got %s = (%s as 100th's round)");
|
||||||
|
|
||||||
val = gnc_numeric_create(1535, 1000);
|
val = gnc_numeric_create(1535, 1000);
|
||||||
check_unary_op (gnc_numeric_eq,
|
check_unary_op (gnc_numeric_eq,
|
||||||
gnc_numeric_create (154, 100),
|
gnc_numeric_create (154, 100),
|
||||||
gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
|
gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
|
||||||
val, "expected %s = %s = (%s as 100th's round)");
|
val, "expected %s got %s = (%s as 100th's round)");
|
||||||
|
|
||||||
val = gnc_numeric_create(1545, 1000);
|
val = gnc_numeric_create(1545, 1000);
|
||||||
check_unary_op (gnc_numeric_eq,
|
check_unary_op (gnc_numeric_eq,
|
||||||
gnc_numeric_create (154, 100),
|
gnc_numeric_create (154, 100),
|
||||||
gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
|
gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
|
||||||
val, "expected %s = %s = (%s as 100th's round)");
|
val, "expected %s got %s = (%s as 100th's round)");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ======================================================= */
|
/* ======================================================= */
|
||||||
@ -384,11 +384,11 @@ check_neg (void)
|
|||||||
|
|
||||||
check_unary_op (gnc_numeric_eq,
|
check_unary_op (gnc_numeric_eq,
|
||||||
gnc_numeric_create (-2, 6), c,
|
gnc_numeric_create (-2, 6), c,
|
||||||
a, "expected %s = %s = -(%s)");
|
a, "expected %s got %s = -(%s)");
|
||||||
|
|
||||||
check_unary_op (gnc_numeric_eq,
|
check_unary_op (gnc_numeric_eq,
|
||||||
gnc_numeric_create (-1, 4), d,
|
gnc_numeric_create (-1, 4), d,
|
||||||
b, "expected %s = %s = -(%s)");
|
b, "expected %s got %s = -(%s)");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -546,6 +546,21 @@ check_add_subtract (void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const gint64 pten[] = { 1, 10, 100, 1000, 10000, 100000, 1000000,
|
||||||
|
10000000, 100000000, 1000000000, 10000000000,
|
||||||
|
100000000000, 1000000000000, 10000000000000,
|
||||||
|
100000000000000, 10000000000000000,
|
||||||
|
100000000000000000, 1000000000000000000};
|
||||||
|
#define POWTEN_OVERFLOW -5
|
||||||
|
|
||||||
|
static inline gint64
|
||||||
|
powten (int exp)
|
||||||
|
{
|
||||||
|
if (exp > 18 || exp < -18)
|
||||||
|
return POWTEN_OVERFLOW;
|
||||||
|
return exp < 0 ? -pten[-exp] : pten[exp];
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
check_add_subtract_overflow (void)
|
check_add_subtract_overflow (void)
|
||||||
{
|
{
|
||||||
@ -565,8 +580,8 @@ check_add_subtract_overflow (void)
|
|||||||
gint64 bin_deno_a = (1 << exp_a);
|
gint64 bin_deno_a = (1 << exp_a);
|
||||||
gint64 bin_deno_b = (1 << exp_a);
|
gint64 bin_deno_b = (1 << exp_a);
|
||||||
*/
|
*/
|
||||||
gint64 dec_deno_a = pwr64 (10, exp_a % 7);
|
gint64 dec_deno_a = powten (exp_a % 7);
|
||||||
gint64 dec_deno_b = pwr64 (10, exp_b % 7);
|
gint64 dec_deno_b = powten (exp_b % 7);
|
||||||
gint64 na = get_random_gint64 () % (1000000 * dec_deno_a);
|
gint64 na = get_random_gint64 () % (1000000 * dec_deno_a);
|
||||||
gint64 nb = get_random_gint64 () % (1000000 * dec_deno_b);
|
gint64 nb = get_random_gint64 () % (1000000 * dec_deno_b);
|
||||||
gnc_numeric result;
|
gnc_numeric result;
|
||||||
@ -808,9 +823,9 @@ check_mult_div (void)
|
|||||||
* an overflow error should be signalled; else the
|
* an overflow error should be signalled; else the
|
||||||
* divide routine should shift down the results till
|
* divide routine should shift down the results till
|
||||||
* the overflow is eliminated.
|
* the overflow is eliminated.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
check_binary_op (gnc_numeric_error (GNC_ERROR_OVERFLOW),
|
/* Doesn't overflow any more! */
|
||||||
|
check_binary_op (gnc_numeric_error (GNC_ERROR_REMAINDER),
|
||||||
gnc_numeric_div(a, b, GNC_DENOM_AUTO,
|
gnc_numeric_div(a, b, GNC_DENOM_AUTO,
|
||||||
GNC_HOW_RND_NEVER | GNC_HOW_DENOM_EXACT),
|
GNC_HOW_RND_NEVER | GNC_HOW_DENOM_EXACT),
|
||||||
a, b, "expected %s got %s = %s / %s for div exact");
|
a, b, "expected %s got %s = %s / %s for div exact");
|
||||||
@ -869,7 +884,7 @@ check_mult_div (void)
|
|||||||
val_a = gnc_numeric_mul (frac, val_tot,
|
val_a = gnc_numeric_mul (frac, val_tot,
|
||||||
gnc_numeric_denom(val_tot),
|
gnc_numeric_denom(val_tot),
|
||||||
GNC_HOW_RND_ROUND | GNC_HOW_DENOM_EXACT);
|
GNC_HOW_RND_ROUND | GNC_HOW_DENOM_EXACT);
|
||||||
check_binary_op (gnc_numeric_create(562854125307LL, 100),
|
check_binary_op (gnc_numeric_create(562854124919LL, 100),
|
||||||
val_a, val_tot, frac,
|
val_a, val_tot, frac,
|
||||||
"expected %s got %s = %s * %s for mult round");
|
"expected %s got %s = %s * %s for mult round");
|
||||||
|
|
||||||
@ -897,7 +912,7 @@ check_reciprocal(void)
|
|||||||
check_unary_op (gnc_numeric_eq, gnc_numeric_create (-3, -1),
|
check_unary_op (gnc_numeric_eq, gnc_numeric_create (-3, -1),
|
||||||
gnc_numeric_convert(val, GNC_DENOM_RECIPROCAL(1),
|
gnc_numeric_convert(val, GNC_DENOM_RECIPROCAL(1),
|
||||||
GNC_HOW_RND_NEVER),
|
GNC_HOW_RND_NEVER),
|
||||||
val, "expected %s = %s = (%s as RECIP(1))");
|
val, "expected %s got %s = (%s as RECIP(1))");
|
||||||
|
|
||||||
a = gnc_numeric_create(200, 100);
|
a = gnc_numeric_create(200, 100);
|
||||||
b = gnc_numeric_create(300, 100);
|
b = gnc_numeric_create(300, 100);
|
||||||
|
@ -1683,6 +1683,7 @@ test_xaccSplitGetSharePrice (Fixture *fixture, gconstpointer pData)
|
|||||||
g_assert_cmpint (check.hits, ==, 0);
|
g_assert_cmpint (check.hits, ==, 0);
|
||||||
|
|
||||||
/* Now invent some value/ammount pairs which cause numeric errors to test the limits */
|
/* Now invent some value/ammount pairs which cause numeric errors to test the limits */
|
||||||
|
/* This one was supposed to overflow, but it doesn't any more.
|
||||||
split->amount = gnc_numeric_create (987654321, 10);
|
split->amount = gnc_numeric_create (987654321, 10);
|
||||||
split->value = gnc_numeric_create (3, 789304166);
|
split->value = gnc_numeric_create (3, 789304166);
|
||||||
quotient = gnc_numeric_div (split->value, split->amount,
|
quotient = gnc_numeric_div (split->value, split->amount,
|
||||||
@ -1702,7 +1703,7 @@ test_xaccSplitGetSharePrice (Fixture *fixture, gconstpointer pData)
|
|||||||
g_assert (gnc_numeric_equal (result, expected));
|
g_assert (gnc_numeric_equal (result, expected));
|
||||||
g_assert_cmpint (check.hits, ==, 2);
|
g_assert_cmpint (check.hits, ==, 2);
|
||||||
g_free (check.msg);
|
g_free (check.msg);
|
||||||
|
*/
|
||||||
split->amount = gnc_numeric_create (987654321, 10);
|
split->amount = gnc_numeric_create (987654321, 10);
|
||||||
split->value = gnc_numeric_create (3, 0);
|
split->value = gnc_numeric_create (3, 0);
|
||||||
quotient = gnc_numeric_div (split->value, split->amount,
|
quotient = gnc_numeric_div (split->value, split->amount,
|
||||||
@ -1720,7 +1721,7 @@ test_xaccSplitGetSharePrice (Fixture *fixture, gconstpointer pData)
|
|||||||
expected = gnc_numeric_create (0, 1);
|
expected = gnc_numeric_create (0, 1);
|
||||||
result = xaccSplitGetSharePrice (split);
|
result = xaccSplitGetSharePrice (split);
|
||||||
g_assert (gnc_numeric_equal (result, expected));
|
g_assert (gnc_numeric_equal (result, expected));
|
||||||
g_assert_cmpint (check.hits, ==, 4);
|
g_assert_cmpint (check.hits, ==, 2);
|
||||||
g_free (check.msg);
|
g_free (check.msg);
|
||||||
|
|
||||||
split->amount = gnc_numeric_create (9, 0);
|
split->amount = gnc_numeric_create (9, 0);
|
||||||
@ -1740,7 +1741,7 @@ test_xaccSplitGetSharePrice (Fixture *fixture, gconstpointer pData)
|
|||||||
expected = gnc_numeric_create (0, 1);
|
expected = gnc_numeric_create (0, 1);
|
||||||
result = xaccSplitGetSharePrice (split);
|
result = xaccSplitGetSharePrice (split);
|
||||||
g_assert (gnc_numeric_equal (result, expected));
|
g_assert (gnc_numeric_equal (result, expected));
|
||||||
g_assert_cmpint (check.hits, ==, 6);
|
g_assert_cmpint (check.hits, ==, 4);
|
||||||
g_free (check.msg);
|
g_free (check.msg);
|
||||||
|
|
||||||
g_log_remove_handler (logdomain, hdlr);
|
g_log_remove_handler (logdomain, hdlr);
|
||||||
|
@ -1262,7 +1262,7 @@ test_xaccTransGetAccountConvRate (Fixture *fixture, gconstpointer pData)
|
|||||||
g_assert_cmpint (check->hits, ==, 0);
|
g_assert_cmpint (check->hits, ==, 0);
|
||||||
split1->value = gnc_numeric_zero();
|
split1->value = gnc_numeric_zero();
|
||||||
rate = xaccTransGetAccountConvRate (fixture->txn, fixture->acc1);
|
rate = xaccTransGetAccountConvRate (fixture->txn, fixture->acc1);
|
||||||
g_assert_cmpint (gnc_numeric_check (rate), ==, GNC_ERROR_ARG);
|
g_assert_cmpint (gnc_numeric_check (rate), ==, GNC_ERROR_OVERFLOW);
|
||||||
g_assert_cmpint (check->hits, ==, 1);
|
g_assert_cmpint (check->hits, ==, 1);
|
||||||
}
|
}
|
||||||
/* xaccTransGetAccountBalance
|
/* xaccTransGetAccountBalance
|
||||||
|
@ -36,6 +36,7 @@ libgnc_qof_la_SOURCES = \
|
|||||||
qofevent.cpp \
|
qofevent.cpp \
|
||||||
qofid.cpp \
|
qofid.cpp \
|
||||||
qofinstance.cpp \
|
qofinstance.cpp \
|
||||||
|
qofint128.cpp \
|
||||||
qoflog.cpp \
|
qoflog.cpp \
|
||||||
qofobject.cpp \
|
qofobject.cpp \
|
||||||
qofquery.cpp \
|
qofquery.cpp \
|
||||||
@ -79,7 +80,7 @@ noinst_HEADERS = \
|
|||||||
qofbook-p.h \
|
qofbook-p.h \
|
||||||
qofclass-p.h \
|
qofclass-p.h \
|
||||||
qofevent-p.h \
|
qofevent-p.h \
|
||||||
qofmath128-p.h \
|
qofint128.hpp \
|
||||||
qofobject-p.h \
|
qofobject-p.h \
|
||||||
qofquery-p.h \
|
qofquery-p.h \
|
||||||
qofquerycore-p.h \
|
qofquerycore-p.h \
|
||||||
@ -94,12 +95,4 @@ else
|
|||||||
EXTRA_DIST += qof-win32.cpp
|
EXTRA_DIST += qof-win32.cpp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
## For testing the qofmath128 routines
|
|
||||||
# run "make check" (to build the test program) and then run test-qofmath
|
|
||||||
check_PROGRAMS = test-qofmath
|
|
||||||
test_qofmath_SOURCES = gnc-numeric.cpp
|
|
||||||
test_qofmath_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_128_BIT_MULT
|
|
||||||
test_qofmath_LDFLAGS = $(libgnc_qof_la_LDFLAGS)
|
|
||||||
test_qofmath_LDADD = $(libgnc_qof_common_libs)
|
|
||||||
|
|
||||||
AM_CPPFLAGS += -DG_LOG_DOMAIN=\"qof\"
|
AM_CPPFLAGS += -DG_LOG_DOMAIN=\"qof\"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -516,14 +516,6 @@ gboolean gnc_numeric_to_decimal(gnc_numeric * a,
|
|||||||
GType gnc_numeric_get_type( void );
|
GType gnc_numeric_get_type( void );
|
||||||
#define GNC_TYPE_NUMERIC (gnc_numeric_get_type ())
|
#define GNC_TYPE_NUMERIC (gnc_numeric_get_type ())
|
||||||
|
|
||||||
/** @} */
|
|
||||||
/** Int 64 exponentiation. Faster and more robust than casting the result of pow().
|
|
||||||
* @param op The number to raise to exp.
|
|
||||||
* @param exp The exponent
|
|
||||||
* @return A gint64
|
|
||||||
*/
|
|
||||||
gint64 pwr64 (gint64 op, int exp);
|
|
||||||
/** @} */
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user