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;
}
Exemple #3
0
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");
    }
}
Exemple #6
0
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;
}