static void check_unary_op_r (gboolean (*eqtest) (gnc_numeric, gnc_numeric), gnc_numeric expected, gnc_numeric actual, gnc_numeric input, const char * errmsg, int line) { char *e = gnc_numeric_print (expected); char *r = gnc_numeric_print (actual); char *a = gnc_numeric_print (input); char *str = g_strdup_printf (errmsg, e, r, a); do_test_call (eqtest(expected, actual), str, __FILE__, line); g_free (a); g_free (r); g_free (e); g_free (str); }
static void check_binary_op_r (gnc_numeric expected, gnc_numeric actual, gnc_numeric input_a, gnc_numeric input_b, const char * errmsg, int line, gboolean (*eq)(gnc_numeric, gnc_numeric)) { char *e = gnc_numeric_print (expected); char *r = gnc_numeric_print (actual); char *a = gnc_numeric_print (input_a); char *b = gnc_numeric_print (input_b); char *str = g_strdup_printf (errmsg, e, r, a, b); do_test_call ((eq)(expected, actual), str, __FILE__, line); g_free (a); g_free (b); g_free (r); g_free (e); g_free (str); }
static void check_mult_div (void) { int i, j; gint64 v; gnc_numeric c, d; gnc_numeric amt_a, amt_tot, frac, val_tot, val_a; gnc_numeric a, b; a = gnc_numeric_create(-100, 100); b = gnc_numeric_create(1, 1); check_binary_op (gnc_numeric_create(-100, 100), gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT), a, b, "expected %s got %s = %s / %s div exact"); a = gnc_numeric_create(-100, 100); b = gnc_numeric_create(-1, 1); check_binary_op (gnc_numeric_create(100, 100), gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT), a, b, "expected %s got %s = %s / %s div exact"); a = gnc_numeric_create(-100, 100); b = gnc_numeric_create(-1, 1); check_binary_op (gnc_numeric_create(100, 100), gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT), a, b, "expected %s got %s = %s * %s mult exact"); a = gnc_numeric_create(2, 6); b = gnc_numeric_create(1, 4); check_binary_op (gnc_numeric_create(2, 24), 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_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_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_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_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_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_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_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), gnc_numeric_print(err)); #endif /* Check for math with 2^63 < num*num < 2^64 which previously failed * see http://bugzilla.gnome.org/show_bug.cgi?id=144980 */ v = 1000000; a = gnc_numeric_create(1 * v, v); b = gnc_numeric_create(10000000 * v, v); check_binary_op (b, 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 * RAND_MAX is approx 2^32 */ for (i = 0; i < NREPS; i++) { gint64 deno = 1; gint64 na = rand(); gint64 nb = rand(); gint64 ne; /* avoid 0 */ if (nb / 4 == 0) { i--; continue; } /* avoid overflow; */ na /= 2; nb /= 2; ne = na * nb; a = gnc_numeric_create(na, deno); b = gnc_numeric_create(nb, deno); check_binary_op_equal (gnc_numeric_create(ne, 1), 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 */ for (j = 1; j < 31; j++) { 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_HOW_DENOM_REDUCE), a, b, "expected %s got %s = %s * %s for mult reduce"); } /* Do some hokey random 128-bit division too */ b = gnc_numeric_create(deno, nb); check_binary_op_equal (gnc_numeric_create(ne, 1), 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; */ na /= 2; nb /= 2; ne = na * nb; for (j = 1; j < 16; j++) { 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_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, 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) * 2222554708930978 = 2 * 1111277354465489 * (yes, that's a sixteen-digit prime number) * 89025 = 3*5*5*1187 * 85568= 64*7*191 * 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. */ /* 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"); 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), c, d, "expected %s got %s = %s / %s for div round"); /* If we specify GNC_HOW_RND_NEVER, then we shoukld get an error, * since the exact result won't fit into a 64-bit quantity. */ check_binary_op (gnc_numeric_error (GNC_ERROR_REMAINDER), gnc_numeric_div(c, d, 82718, GNC_HOW_DENOM_EXACT | GNC_HOW_RND_NEVER), c, d, "expected %s got %s = %s / %s for div round"); /* A simple irreducible ratio, involving negative numbers */ amt_a = gnc_numeric_create (-6005287905LL, 40595); amt_tot = gnc_numeric_create (-8744187958LL, 40595); frac = gnc_numeric_div (amt_a, amt_tot, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE); check_binary_op (gnc_numeric_create(6005287905LL, 8744187958LL), frac, amt_a, amt_tot, "expected %s got %s = %s / %s for div reduce"); /* Another overflow-prone condition */ val_tot = gnc_numeric_create (-4280656418LL, 19873); 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(-2939846940LL, 19873), val_a, val_tot, frac, "expected %s got %s = %s * %s for mult round"); frac = gnc_numeric_create (396226789777979LL, 328758834367851752LL); val_tot = gnc_numeric_create (467013515494988LL, 100); 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(562854124919LL, 100), val_a, val_tot, frac, "expected %s got %s = %s * %s for mult round"); /* Yet another bug from bugzilla ... */ a = gnc_numeric_create (40066447153986554LL, 4518); b = gnc_numeric_create (26703286457229LL, 3192); frac = gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_SIGFIGS(6) | GNC_HOW_RND_ROUND); check_binary_op (gnc_numeric_create(106007, 100), frac, a, b, "expected %s got %s = %s / %s for mult sigfigs"); }
int main(int argc, char ** argv) { gnc_numeric a = gnc_numeric_create(1, 3); gnc_numeric b = gnc_numeric_create(1, 4); gnc_numeric c; gnc_numeric 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_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), gnc_numeric_print(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_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), gnc_numeric_print(err)); printf("multiply (EXACT): %s * %s = %s\n", gnc_numeric_print(a), gnc_numeric_print(b), gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT))); printf("multiply (REDUCE): %s * %s = %s\n", gnc_numeric_print(a), gnc_numeric_print(b), gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE))); return 0; }
static void check_add_subtract (void) { int i; gnc_numeric a, b, c, d, z; #if CHECK_ERRORS_TOO gnc_numeric c; #endif a = gnc_numeric_create(2, 6); b = gnc_numeric_create(1, 4); /* 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_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_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_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_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_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_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_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_HOW_RND_ROUND), a, b, "expected %s got %s = %s - %s for sub 100ths (banker's)"); /* ------------------------------------------------------------ */ /* This test has failed before */ c = gnc_numeric_neg (a); d = gnc_numeric_neg (b); z = gnc_numeric_zero(); check_binary_op (c, gnc_numeric_add_fixed(z, c), z, c, "expected %s got %s = %s + %s for add fixed"); check_binary_op (d, gnc_numeric_add_fixed(z, d), z, d, "expected %s got %s = %s + %s for add fixed"); /* ------------------------------------------------------------ */ /* Same as above, but with signs reviersed */ a = c; b = d; /* 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_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_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_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_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_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_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_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_HOW_RND_ROUND), a, b, "expected %s got %s = %s - %s for sub 100ths (banker's)"); /* ------------------------------------------------------------ */ #if CHECK_ERRORS_TOO 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_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), gnc_numeric_print(err)); #endif /* ------------------------------------------------------------ */ /* Add and subtract some random numbers */ for (i = 0; i < NREPS; i++) { gnc_numeric e; gint64 deno = rand() + 1; gint64 na = get_random_gint64(); gint64 nb = get_random_gint64(); gint64 ne; /* avoid overflow; */ na /= 2; nb /= 2; a = gnc_numeric_create(na, deno); b = gnc_numeric_create(nb, deno); /* Add */ ne = na + nb; e = gnc_numeric_create(ne, deno); check_binary_op (e, 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_HOW_DENOM_EXACT), a, b, "expected %s got %s = %s - %s for exact subtraction"); } }