static void check_double (void) { double flo; gnc_numeric val = gnc_numeric_create (0, 1); check_unary_op (gnc_numeric_eq, gnc_numeric_create (112346, 100000), double_to_gnc_numeric(1.1234567890123, GNC_DENOM_AUTO, 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_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_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_HOW_DENOM_SIGFIGS(6) | GNC_HOW_RND_ROUND), val, "expected %s = %s double 6 figs"); flo = gnc_numeric_to_double(gnc_numeric_create(7, 16)); do_test ((0.4375 == flo), "float pt conversion"); }
// Share Price / Conversion factor static gchar* add_price (gchar *so_far, Split *split, gboolean t_void, CsvExportInfo *info) { const gchar *string_amount; gchar *conv; gchar *result; if (t_void) { gnc_numeric cf = gnc_numeric_div (xaccSplitVoidFormerValue (split), xaccSplitVoidFormerAmount (split), GNC_DENOM_AUTO, GNC_HOW_DENOM_SIGFIGS(6) | GNC_HOW_RND_ROUND_HALF_UP); string_amount = xaccPrintAmount (cf, gnc_split_amount_print_info (split, FALSE)); } else string_amount = xaccPrintAmount (xaccSplitGetSharePrice (split), gnc_split_amount_print_info (split, FALSE)); conv = csv_txn_test_field_string (info, string_amount); result = g_strconcat (so_far, conv, info->end_sep, EOLSTR, NULL); g_free (conv); return result; }
gnc_numeric gnc_euro_currency_get_rate (const gnc_commodity *currency) { gnc_euro_rate_struct * result; if (currency == NULL) return gnc_numeric_zero (); if (!gnc_commodity_is_iso(currency)) return gnc_numeric_zero (); result = bsearch(currency, gnc_euro_rates, sizeof(gnc_euro_rates) / sizeof(gnc_euro_rate_struct), sizeof(gnc_euro_rate_struct), gnc_euro_rate_compare); if (result == NULL) return gnc_numeric_zero (); return double_to_gnc_numeric (result->rate, GNC_DENOM_AUTO, GNC_HOW_DENOM_SIGFIGS(6) | GNC_HOW_RND_ROUND_HALF_UP); }
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"); /* Check for math with 2^63 < num*num < 2^64 which previously failed * see https://bugs.gnucash.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(INT64_C(1173888083434299), 93773); b = gnc_numeric_create(INT64_C(2222554708930978), 89579); /* 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 into primes: * 1173888083434299 = 3 * 2283317 * 171371749 * (yes, thats a seven and a nine digit prime) * 2222554708930978 = 2 * 1111277354465489 * (yes, that's a sixteen-digit prime number) * 93773 = 79*1187 * 89579 = 67*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. */ check_binary_op (gnc_numeric_error (GNC_ERROR_OVERFLOW), 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(504548, 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_REDUCE); 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_REDUCE); 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"); }
static void check_add_subtract (void) { int i; gnc_numeric a, b, c, d, z; 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)"); /* ------------------------------------------------------------ */ /* 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"); } }
static void* func_op(const char *fname, int argc, void **argv) { SCM scmFn, scmArgs, scmTmp; int i; var_store *vs; gchar *str; gnc_numeric n, *result; GString *realFnName; realFnName = g_string_sized_new( strlen(fname) + 5 ); g_string_printf( realFnName, "gnc:%s", fname ); scmFn = scm_internal_catch(SCM_BOOL_T, (scm_t_catch_body)scm_c_eval_string, realFnName->str, scm_handle_by_message_noexit, NULL); g_string_free( realFnName, TRUE ); if (!scm_is_procedure(scmFn)) { /* FIXME: handle errors correctly. */ printf( "gnc:\"%s\" is not a scm procedure\n", fname ); return NULL; } scmArgs = scm_listify( SCM_UNDEFINED ); for ( i = 0; i < argc; i++ ) { /* cons together back-to-front. */ vs = (var_store*)argv[argc - i - 1]; switch ( vs->type ) { case VST_NUMERIC: n = *(gnc_numeric*)(vs->value); scmTmp = scm_make_real( gnc_numeric_to_double( n ) ); break; case VST_STRING: str = (char*)(vs->value); scmTmp = scm_mem2string( str, strlen(str) ); break; default: /* FIXME: error */ printf( "argument %d not a numeric or string [type = %d]\n", i, vs->type ); return NULL; break; /* notreached */ } scmArgs = scm_cons( scmTmp, scmArgs ); } //scmTmp = scm_apply(scmFn, scmArgs , SCM_EOL); scmTmp = gfec_apply(scmFn, scmArgs, _exception_handler); if (_function_evaluation_error_msg != NULL) { PERR("function eval error: [%s]\n", _function_evaluation_error_msg); _function_evaluation_error_msg = NULL; return NULL; } result = g_new0( gnc_numeric, 1 ); *result = double_to_gnc_numeric( scm_num2dbl(scmTmp, G_STRFUNC), GNC_DENOM_AUTO, GNC_HOW_DENOM_SIGFIGS(6) | GNC_HOW_RND_ROUND ); /* FIXME: cleanup scmArgs = scm_list, cons'ed cells? */ return (void*)result; }