[Gnucash-changes] add new/improved rounding/overflow test replace
'old' GNC_RND tokens
Linas Vepstas
linas at cvs.gnucash.org
Tue Jun 29 10:44:42 EDT 2004
Log Message:
-----------
add new/improved rounding/overflow test
replace 'old' GNC_RND tokens with new GNC_HOW_RND
Modified Files:
--------------
gnucash/src/engine/test:
test-numeric.c
Revision Data
-------------
Index: test-numeric.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/test/test-numeric.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -Lsrc/engine/test/test-numeric.c -Lsrc/engine/test/test-numeric.c -u -r1.12 -r1.13
--- src/engine/test/test-numeric.c
+++ src/engine/test/test-numeric.c
@@ -239,56 +239,56 @@
val = gnc_numeric_create(7, 16);
check_unary_op (gnc_numeric_eq,
gnc_numeric_create (43,100),
- gnc_numeric_convert (val, 100, GNC_RND_FLOOR),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_FLOOR),
val, "expected %s = %s = (%s as 100th's floor)");
check_unary_op (gnc_numeric_eq,
gnc_numeric_create (44,100),
- gnc_numeric_convert (val, 100, GNC_RND_CEIL),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_CEIL),
val, "expected %s = %s = (%s as 100th's ceiling)");
check_unary_op (gnc_numeric_eq,
gnc_numeric_create (43,100),
- gnc_numeric_convert (val, 100, GNC_RND_TRUNC),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_TRUNC),
val, "expected %s = %s = (%s as 100th's trunc)");
check_unary_op (gnc_numeric_eq,
gnc_numeric_create (44,100),
- gnc_numeric_convert (val, 100, GNC_RND_ROUND),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
val, "expected %s = %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_RND_ROUND),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
val, "expected %s = %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_RND_ROUND),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
val, "expected %s = %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_RND_ROUND),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
val, "expected %s = %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_RND_ROUND),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
val, "expected %s = %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_RND_ROUND),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
val, "expected %s = %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_RND_ROUND),
+ gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
val, "expected %s = %s = (%s as 100th's round)");
}
@@ -303,31 +303,31 @@
gnc_numeric_create (112346,100000),
double_to_gnc_numeric(1.1234567890123,
GNC_DENOM_AUTO,
- GNC_DENOM_SIGFIGS(6) |
- GNC_RND_ROUND),
+ GNC_HOW_DENOM_SIGFIGS(6) |
+ GNC_HOW_RND_ROUND),
val, "expected %s = %s double 6 figs");
check_unary_op (gnc_numeric_eq,
gnc_numeric_create (112346,10000000),
double_to_gnc_numeric(0.011234567890123,
GNC_DENOM_AUTO,
- GNC_DENOM_SIGFIGS(6) |
- GNC_RND_ROUND),
+ GNC_HOW_DENOM_SIGFIGS(6) |
+ GNC_HOW_RND_ROUND),
val, "expected %s = %s double 6 figs");
check_unary_op (gnc_numeric_eq,
gnc_numeric_create (112346,100),
double_to_gnc_numeric(1123.4567890123,
GNC_DENOM_AUTO,
- GNC_DENOM_SIGFIGS(6) |
- GNC_RND_ROUND),
+ GNC_HOW_DENOM_SIGFIGS(6) |
+ GNC_HOW_RND_ROUND),
val, "expected %s = %s double 6 figs");
check_unary_op (gnc_numeric_eq,
gnc_numeric_create (112346,10000000000LL),
double_to_gnc_numeric(1.1234567890123e-5,
GNC_DENOM_AUTO,
- GNC_DENOM_SIGFIGS(6) |
- GNC_RND_ROUND),
+ GNC_HOW_DENOM_SIGFIGS(6) |
+ GNC_HOW_RND_ROUND),
val, "expected %s = %s double 6 figs");
double flo = gnc_numeric_to_double(gnc_numeric_create(7, 16));
@@ -344,51 +344,51 @@
/* Well, actually 14/24 would be acceptable/better in this case */
check_binary_op (gnc_numeric_create(7,12),
- gnc_numeric_add(a, b, GNC_DENOM_AUTO, GNC_DENOM_EXACT),
+ gnc_numeric_add(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
a, b, "expected %s got %s = %s + %s for add exact");
check_binary_op (gnc_numeric_create(58,100),
- gnc_numeric_add(a, b, 100, GNC_RND_ROUND),
+ gnc_numeric_add(a, b, 100, GNC_HOW_RND_ROUND),
a, b, "expected %s got %s = %s + %s for add 100ths (banker's)");
check_binary_op (gnc_numeric_create(5833,10000),
gnc_numeric_add(a, b, GNC_DENOM_AUTO,
- GNC_DENOM_SIGFIGS(4) |
- GNC_RND_ROUND),
+ GNC_HOW_DENOM_SIGFIGS(4) |
+ GNC_HOW_RND_ROUND),
a, b, "expected %s got %s = %s + %s for add 4 sig figs");
check_binary_op (gnc_numeric_create(583333,1000000),
gnc_numeric_add(a, b, GNC_DENOM_AUTO,
- GNC_DENOM_SIGFIGS(6) |
- GNC_RND_ROUND),
+ GNC_HOW_DENOM_SIGFIGS(6) |
+ GNC_HOW_RND_ROUND),
a, b, "expected %s got %s = %s + %s for add 6 sig figs");
check_binary_op (gnc_numeric_create(1,12),
- gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_DENOM_EXACT),
+ gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
a, b, "expected %s got %s = %s - %s for sub exact");
/* We should try something trickier for reduce & lcd */
check_binary_op (gnc_numeric_create(1,12),
- gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_DENOM_REDUCE),
+ gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE),
a, b, "expected %s got %s = %s - %s for sub reduce");
check_binary_op (gnc_numeric_create(1,12),
- gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_DENOM_LCD),
+ gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD),
a, b, "expected %s got %s = %s - %s for sub reduce");
check_binary_op (gnc_numeric_create(8,100),
- gnc_numeric_sub(a, b, 100, GNC_RND_ROUND),
+ gnc_numeric_sub(a, b, 100, GNC_HOW_RND_ROUND),
a, b, "expected %s got %s = %s - %s for sub 100ths (banker's)");
#if CHECK_ERRORS_TOO
gnc_numeric c;
- c = gnc_numeric_add_with_error(a, b, 100, GNC_RND_ROUND, &err);
+ c = gnc_numeric_add_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err);
printf("add 100ths/error : %s + %s = %s + (error) %s\n\n",
gnc_numeric_print(a), gnc_numeric_print(b),
gnc_numeric_print(c),
gnc_numeric_print(err));
- c = gnc_numeric_sub_with_error(a, b, 100, GNC_RND_FLOOR, &err);
+ c = gnc_numeric_sub_with_error(a, b, 100, GNC_HOW_RND_FLOOR, &err);
printf("sub 100ths/error : %s - %s = %s + (error) %s\n\n",
gnc_numeric_print(a), gnc_numeric_print(b),
gnc_numeric_print(c),
@@ -417,14 +417,14 @@
ne = na+nb;
e = gnc_numeric_create(ne, deno);
check_binary_op (e,
- gnc_numeric_add(a, b, GNC_DENOM_AUTO, GNC_DENOM_EXACT),
+ gnc_numeric_add(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
a, b, "expected %s got %s = %s + %s for exact addition");
/* Subtract */
ne = na-nb;
e = gnc_numeric_create(ne, deno);
check_binary_op (e,
- gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_DENOM_EXACT),
+ gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
a, b, "expected %s got %s = %s - %s for exact subtraction");
}
}
@@ -434,42 +434,43 @@
static void
check_mult_div (void)
{
+ gnc_numeric c, d;
gnc_numeric a = gnc_numeric_create(2, 6);
gnc_numeric b = gnc_numeric_create(1, 4);
check_binary_op (gnc_numeric_create(2,24),
- gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_DENOM_EXACT),
+ gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
a, b, "expected %s got %s = %s * %s for mult exact");
check_binary_op (gnc_numeric_create(1,12),
- gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_DENOM_REDUCE),
+ gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE),
a, b, "expected %s got %s = %s * %s for mult reduce");
check_binary_op (gnc_numeric_create(8,100),
- gnc_numeric_mul(a, b, 100, GNC_RND_ROUND),
+ gnc_numeric_mul(a, b, 100, GNC_HOW_RND_ROUND),
a, b, "expected %s got %s = %s * %s for mult 100th's");
check_binary_op (gnc_numeric_create(8,6),
- gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_DENOM_EXACT),
+ gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
a, b, "expected %s got %s = %s / %s for div exact");
check_binary_op (gnc_numeric_create(4,3),
- gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_DENOM_REDUCE),
+ gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE),
a, b, "expected %s got %s = %s / %s for div reduce");
check_binary_op (gnc_numeric_create(133,100),
- gnc_numeric_div(a, b, 100, GNC_RND_ROUND),
+ gnc_numeric_div(a, b, 100, GNC_HOW_RND_ROUND),
a, b, "expected %s got %s = %s * %s for div 100th's");
#if CHECK_ERRORS_TOO
gnc_numeric c;
- c = gnc_numeric_mul_with_error(a, b, 100, GNC_RND_ROUND, &err);
+ c = gnc_numeric_mul_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err);
printf("mul 100ths/error : %s * %s = %s + (error) %s\n\n",
gnc_numeric_print(a), gnc_numeric_print(b),
gnc_numeric_print(c),
gnc_numeric_print(err));
- c = gnc_numeric_div_with_error(a, b, 100, GNC_RND_ROUND, &err);
+ c = gnc_numeric_div_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err);
printf("div 100ths/error : %s / %s = %s + (error) %s\n\n",
gnc_numeric_print(a), gnc_numeric_print(b),
gnc_numeric_print(c),
@@ -485,7 +486,7 @@
b = gnc_numeric_create(10000000*v, v);
check_binary_op (b,
- gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_DENOM_LCD),
+ gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD),
a, b, "expected %s got %s = %s * %s for multiply");
/* Multiply some random numbers. This test presumes that
@@ -508,7 +509,7 @@
b = gnc_numeric_create(nb, deno);
check_binary_op (gnc_numeric_create(ne,1),
- gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_DENOM_EXACT),
+ gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
a, b, "expected %s got %s = %s * %s for mult exact");
/* Force 128-bit math to come into play */
@@ -518,7 +519,7 @@
a = gnc_numeric_create(na << j, 1<<j);
b = gnc_numeric_create(nb << j, 1<<j);
check_binary_op (gnc_numeric_create(ne, 1),
- gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_DENOM_REDUCE),
+ gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE),
a, b, "expected %s got %s = %s * %s for mult reduce");
}
@@ -526,7 +527,7 @@
b = gnc_numeric_create(deno, nb);
check_binary_op (gnc_numeric_create(ne,1),
- gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_DENOM_EXACT),
+ gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
a, b, "expected %s got %s = %s / %s for div exact");
/* avoid overflow; */
@@ -538,14 +539,16 @@
a = gnc_numeric_create(na << j, 1<<j);
b = gnc_numeric_create(1<<j, nb << j);
check_binary_op (gnc_numeric_create(ne, 1),
- gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_DENOM_REDUCE),
+ gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE),
a, b, "expected %s got %s = %s / %s for div reduce");
}
}
a = gnc_numeric_create(782592055622866ULL,89025);
b = gnc_numeric_create(2222554708930978ULL,85568);
- /* Dividing the above pair overflows. This can be seen from
+ /* Dividing the above pair overflows, in that after
+ * the division the denominator won't fit into a
+ * 64-bit quantity. This can be seen from
* the factorization int primes:
* 782592055622866 = 2 * 2283317 * 171371749
* (yes, thats a seven and a nine digit prime)
@@ -553,11 +556,45 @@
* (yes, that's a sixteen-digit prime number)
* 89025 = 3*5*5*1187
* 85568= 64*7*191
- * You can do this by hand and see that it overflows.
+ * If the rounding method is exact/no-round, then
+ * 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_create(GNC_ERROR_OVERFLOW, 0),
+ check_binary_op (gnc_numeric_error (GNC_ERROR_OVERFLOW),
gnc_numeric_div(a, b, GNC_DENOM_AUTO,
- GNC_DENOM_SIGFIGS(6) | GNC_RND_ROUND),
+ GNC_HOW_DENOM_EXACT),
+ a, b, "expected %s got %s = %s / %s for div exact");
+
+ check_binary_op (gnc_numeric_create(338441, 1000000),
+ gnc_numeric_div(a, b, GNC_DENOM_AUTO,
+ GNC_HOW_DENOM_SIGFIGS(6) | GNC_HOW_RND_ROUND),
+ a, b, "expected %s got %s = %s / %s for div round");
+
+ /* The below is a 'typical' value calculation:
+ * value_frac = value_tot * amt_frace / amt_tot
+ * and has some typical potential-overflow values.
+ * 82718 = 2 * 59 * 701
+ * 47497125586 = 2 * 1489 * 15949337
+ * 69100955 = 5 * 7 * 11 * 179483
+ * 32005637020 = 4 * 5 * 7 * 43 * 71 * 103 * 727
+ */
+ a = gnc_numeric_create (-47497125586LL, 82718);
+ b = gnc_numeric_create (-69100955LL, 55739);
+ c = gnc_numeric_mul (a,b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
+ d = gnc_numeric_create (-32005637020LL, 55739);
+
+ check_binary_op (gnc_numeric_create(-102547458LL, 82718),
+ gnc_numeric_div(c, d, 82718,
+ GNC_HOW_DENOM_EXACT),
+ a, b, "expected %s got %s = %s / %s for div round");
+
+// XXX this set of tests is not yet working right ...
+// it should be overflowing not rounding
+ check_binary_op (gnc_numeric_error (GNC_ERROR_OVERFLOW),
+ gnc_numeric_div(c, d, 82718,
+ GNC_HOW_DENOM_EXACT|GNC_HOW_RND_NEVER),
a, b, "expected %s got %s = %s / %s for div round");
}
More information about the gnucash-changes
mailing list