Reimplement gnc_numeric with QofInt128

And in a more C++ idiom.
This commit is contained in:
John Ralls 2014-11-29 17:53:41 -08:00
parent ab94094523
commit 33a0c4e968
6 changed files with 369 additions and 755 deletions

View File

@ -153,21 +153,21 @@ check_reduce (void)
check_unary_op (gnc_numeric_eq,
gnc_numeric_create (5011617, 167108327),
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);
rval = gnc_numeric_reduce (val);
check_unary_op (gnc_numeric_eq,
gnc_numeric_create (4 * 17 * 17, 9),
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);
rval = gnc_numeric_reduce (val);
check_unary_op (gnc_numeric_eq,
gnc_numeric_create (1, 1024 * 1024 * 1024),
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);
rval = gnc_numeric_reduce (mval);
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 */
check_unary_op (gnc_numeric_equal,
@ -277,56 +277,56 @@ check_rounding (void)
check_unary_op (gnc_numeric_eq,
gnc_numeric_create (43, 100),
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,
gnc_numeric_create (44, 100),
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,
gnc_numeric_create (43, 100),
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,
gnc_numeric_create (44, 100),
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);
check_unary_op (gnc_numeric_eq,
gnc_numeric_create (151, 100),
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);
check_unary_op (gnc_numeric_eq,
gnc_numeric_create (152, 100),
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 */
val = gnc_numeric_create(1515, 1000);
check_unary_op (gnc_numeric_eq,
gnc_numeric_create (152, 100),
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);
check_unary_op (gnc_numeric_eq,
gnc_numeric_create (152, 100),
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);
check_unary_op (gnc_numeric_eq,
gnc_numeric_create (154, 100),
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);
check_unary_op (gnc_numeric_eq,
gnc_numeric_create (154, 100),
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,
gnc_numeric_create (-2, 6), c,
a, "expected %s = %s = -(%s)");
a, "expected %s got %s = -(%s)");
check_unary_op (gnc_numeric_eq,
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
check_add_subtract_overflow (void)
{
@ -565,8 +580,8 @@ check_add_subtract_overflow (void)
gint64 bin_deno_a = (1 << exp_a);
gint64 bin_deno_b = (1 << exp_a);
*/
gint64 dec_deno_a = pwr64 (10, exp_a % 7);
gint64 dec_deno_b = pwr64 (10, exp_b % 7);
gint64 dec_deno_a = powten (exp_a % 7);
gint64 dec_deno_b = powten (exp_b % 7);
gint64 na = get_random_gint64 () % (1000000 * dec_deno_a);
gint64 nb = get_random_gint64 () % (1000000 * dec_deno_b);
gnc_numeric result;
@ -808,9 +823,9 @@ check_mult_div (void)
* an overflow error should be signalled; else the
* divide routine should shift down the results till
* 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_HOW_RND_NEVER | GNC_HOW_DENOM_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,
gnc_numeric_denom(val_tot),
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,
"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),
gnc_numeric_convert(val, GNC_DENOM_RECIPROCAL(1),
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);
b = gnc_numeric_create(300, 100);

View File

@ -1683,6 +1683,7 @@ test_xaccSplitGetSharePrice (Fixture *fixture, gconstpointer pData)
g_assert_cmpint (check.hits, ==, 0);
/* 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->value = gnc_numeric_create (3, 789304166);
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_cmpint (check.hits, ==, 2);
g_free (check.msg);
*/
split->amount = gnc_numeric_create (987654321, 10);
split->value = gnc_numeric_create (3, 0);
quotient = gnc_numeric_div (split->value, split->amount,
@ -1720,7 +1721,7 @@ test_xaccSplitGetSharePrice (Fixture *fixture, gconstpointer pData)
expected = gnc_numeric_create (0, 1);
result = xaccSplitGetSharePrice (split);
g_assert (gnc_numeric_equal (result, expected));
g_assert_cmpint (check.hits, ==, 4);
g_assert_cmpint (check.hits, ==, 2);
g_free (check.msg);
split->amount = gnc_numeric_create (9, 0);
@ -1740,7 +1741,7 @@ test_xaccSplitGetSharePrice (Fixture *fixture, gconstpointer pData)
expected = gnc_numeric_create (0, 1);
result = xaccSplitGetSharePrice (split);
g_assert (gnc_numeric_equal (result, expected));
g_assert_cmpint (check.hits, ==, 6);
g_assert_cmpint (check.hits, ==, 4);
g_free (check.msg);
g_log_remove_handler (logdomain, hdlr);

View File

@ -1262,7 +1262,7 @@ test_xaccTransGetAccountConvRate (Fixture *fixture, gconstpointer pData)
g_assert_cmpint (check->hits, ==, 0);
split1->value = gnc_numeric_zero();
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);
}
/* xaccTransGetAccountBalance

View File

@ -36,6 +36,7 @@ libgnc_qof_la_SOURCES = \
qofevent.cpp \
qofid.cpp \
qofinstance.cpp \
qofint128.cpp \
qoflog.cpp \
qofobject.cpp \
qofquery.cpp \
@ -79,7 +80,7 @@ noinst_HEADERS = \
qofbook-p.h \
qofclass-p.h \
qofevent-p.h \
qofmath128-p.h \
qofint128.hpp \
qofobject-p.h \
qofquery-p.h \
qofquerycore-p.h \
@ -94,12 +95,4 @@ else
EXTRA_DIST += qof-win32.cpp
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\"

File diff suppressed because it is too large Load Diff

View File

@ -516,14 +516,6 @@ gboolean gnc_numeric_to_decimal(gnc_numeric * a,
GType gnc_numeric_get_type( void );
#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
}
#endif