static void
gnc_template_register_save_shares_cell (BasicCell * cell,
                                        gpointer save_data,
                                        gpointer user_data)
{
    SRSaveData *sd = save_data;
    kvp_frame *kvpf;
    char *sharesStr = "(x + y)/42";

    g_return_if_fail (gnc_basic_cell_has_name (cell, SHRS_CELL));

    kvpf = xaccSplitGetSlots (sd->split);

    /* FIXME: shares cells are numeric by definition. */
    DEBUG ("kvp_frame before: %s\n", kvp_frame_to_string (kvpf));

    /* sharesStr = gnc_numeric_to_string( sharesStr ); */
    kvp_frame_set_slot_path (kvpf,
                             kvp_value_new_string (sharesStr),
                             GNC_SX_ID,
                             GNC_SX_SHARES,
                             NULL);

    DEBUG ("kvp_frame  after: %s\n", kvp_frame_to_string (kvpf));

    /* set the shares to an innocuous value */
    /* Note that this marks the split dirty */
    xaccSplitSetSharePriceAndAmount (sd->split,
                                     gnc_numeric_create (0, 1),
                                     gnc_numeric_create (0, 1));
}
Esempio n. 2
0
/* Make sure that the equivalence operator we use for
 * later tests actually works */
static void
check_eq_operator (void)
{
    gnc_numeric a = gnc_numeric_create (42, 58);
    gnc_numeric b = gnc_numeric_create (42, 58);
    gnc_numeric c = gnc_numeric_create (40, 58);

    /* Check strict equivalence and non-equivalence */
    do_test (gnc_numeric_eq(a, a), "expected self-equivalence");
    do_test (gnc_numeric_eq(a, b), "expected equivalence");
    do_test (0 == gnc_numeric_eq(a, c), "expected inequivalence");
}
Esempio n. 3
0
/* Set the value for the given input amount */
void
gnc_tree_util_set_value_for_amount (GncTreeViewSplitReg *view, Transaction *trans, Split *split, gnc_numeric input)
{
    gnc_numeric  split_rate;
    gnc_numeric  amount;
    gnc_numeric  value, new_value;
    int denom;

    ENTER("trans %p and split %p and input is %s", trans, split, gnc_numeric_to_string (input));

    if (gnc_numeric_zero_p (input))
    {
        xaccSplitSetValue (split, input);
        xaccSplitSetAmount (split, input);
        LEAVE("zero");
        return;
    }

    amount = xaccSplitGetAmount (split);
    value = xaccSplitGetValue (split);

    denom = gtu_sr_get_value_denom (split);

    split_rate = gnc_numeric_div (value, amount, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
    if (gnc_numeric_check (split_rate) != GNC_ERROR_OK)
        split_rate = gnc_numeric_create (100,100);

    new_value = gnc_numeric_mul (input, split_rate, denom, GNC_HOW_RND_ROUND_HALF_UP);

    xaccSplitSetValue (split, new_value);
    xaccSplitSetAmount (split, input);

    LEAVE("");
}
Esempio n. 4
0
static void
test_dom_tree_to_gnc_numeric(void)
{
    int i;

    for (i = 0; i < 20; i++)
    {
        gchar *message = NULL;

        message = test_gnc_nums_internal(get_random_gnc_numeric(GNC_DENOM_AUTO));

        do_test_args(message == NULL, "dom_tree_to_gnc_numeric",
                     __FILE__, __LINE__, message);
    }

    {
        gchar *message = NULL;

        message = test_gnc_nums_internal
                  (gnc_numeric_create(18768786810LL, 100000));

        do_test_args(message == NULL, "gnc_num 18768786810/100000",
                     __FILE__, __LINE__, message);
    }
}
Esempio n. 5
0
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");

    check_unary_op (gnc_numeric_eq,
                    gnc_numeric_create (961600000, 10000000),
                    double_to_gnc_numeric(96.16,
                                          GNC_DENOM_AUTO,
                                          GNC_HOW_DENOM_SIGFIGS(9) |
                                          GNC_HOW_RND_ROUND),
                    val, "expected %s = %s GncNumeric from 96.16");

    check_unary_op (gnc_numeric_eq,
                    gnc_numeric_create (9616000000, 1),
                    double_to_gnc_numeric(9616000000.0,
                                          GNC_DENOM_AUTO,
                                          GNC_HOW_DENOM_SIGFIGS(9) |
                                          GNC_HOW_RND_ROUND),
                    val, "expected %s = %s GncNumeric from 9616000000.0");

    flo = gnc_numeric_to_double(gnc_numeric_create(7, 16));
    do_test ((0.4375 == flo), "float pt conversion");
}
Esempio n. 6
0
static void
check_neg (void)
{
    gnc_numeric a = gnc_numeric_create(2, 6);
    gnc_numeric b = gnc_numeric_create(1, 4);
    gnc_numeric c = gnc_numeric_neg (a);
    gnc_numeric d = gnc_numeric_neg (b);

    check_unary_op (gnc_numeric_eq,
                    gnc_numeric_create (-2, 6), c,
                    a, "expected %s got %s = -(%s)");

    check_unary_op (gnc_numeric_eq,
                    gnc_numeric_create (-1, 4), d,
                    b, "expected %s got %s = -(%s)");

}
Esempio n. 7
0
gnc_numeric
gnc_numeric_neg(gnc_numeric a)
{
    if (gnc_numeric_check(a))
    {
        return gnc_numeric_error(GNC_ERROR_ARG);
    }
    return gnc_numeric_create(- a.num, a.denom);
}
Esempio n. 8
0
gnc_numeric
gnc_numeric_abs(gnc_numeric a)
{
    if (gnc_numeric_check(a))
    {
        return gnc_numeric_error(GNC_ERROR_ARG);
    }
    return gnc_numeric_create(ABS(a.num), a.denom);
}
Esempio n. 9
0
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
gnc_template_register_save_debcred_cell (BasicCell * cell,
        gpointer save_data,
        gpointer user_data)
{
    SRSaveData *sd = save_data;
    SplitRegister *reg = user_data;
    const char *credit_formula, *debit_formula;
    char *error_loc;
    gnc_numeric credit_amount, debit_amount;
    gboolean parse_result;

    g_return_if_fail (gnc_basic_cell_has_name (cell, FDEBT_CELL) ||
                      gnc_basic_cell_has_name (cell, FCRED_CELL));

    if (sd->handled_dc)
        return;

    /* amountStr = gnc_numeric_to_string (new_amount); */

    credit_formula = gnc_table_layout_get_cell_value (reg->table->layout,
						      FCRED_CELL);
    /* If the value can be parsed into a numeric result (without any
     * further variable definitions), store that numeric value
     * additionally in the kvp. Otherwise store a zero numeric
     * there.*/
    parse_result = gnc_exp_parser_parse_separate_vars(credit_formula,
						      &credit_amount,
						      &error_loc, NULL);
    if (!parse_result)
        credit_amount = gnc_numeric_zero();

    debit_formula = gnc_table_layout_get_cell_value (reg->table->layout,
						     FDEBT_CELL);

    /* If the value can be parsed into a numeric result, store that
     * numeric value additionally. See above comment.*/
    parse_result = gnc_exp_parser_parse_separate_vars(debit_formula,
						      &debit_amount,
						      &error_loc, NULL);
    if (!parse_result)
        debit_amount = gnc_numeric_zero();

    qof_instance_set (QOF_INSTANCE (sd->split),
		      "sx-credit-formula", credit_formula,
		      "sx-credit-numeric", &credit_amount,
		      "sx-debit-formula", debit_formula,
		      "sx-debit-numeric", &debit_amount,
		      NULL);
    /* set the amount to an innocuous value */
    /* Note that this marks the split dirty */
    xaccSplitSetValue (sd->split, gnc_numeric_create (0, 1));

    sd->handled_dc = TRUE;
}
Esempio n. 11
0
static void
gnc_template_register_save_shares_cell (BasicCell * cell,
                                        gpointer save_data,
                                        gpointer user_data)
{
    SRSaveData *sd = save_data;
    char *sharesStr = "(x + y)/42";

    g_return_if_fail (gnc_basic_cell_has_name (cell, SHRS_CELL));
    /* FIXME: shares cells are numeric by definition. */
    qof_instance_set (QOF_INSTANCE (sd->split),
		      "sx-shares", sharesStr,
		      NULL);

    /* set the shares to an innocuous value */
    /* Note that this marks the split dirty */
    xaccSplitSetSharePriceAndAmount (sd->split,
                                     gnc_numeric_create (0, 1),
                                     gnc_numeric_create (0, 1));
}
static gnc_numeric
gnc_split_register_get_rate_cell (SplitRegister *reg, const char *cell_name)
{
    PriceCell *rate_cell;

    rate_cell = (PriceCell*) gnc_table_layout_get_cell (reg->table->layout,
                cell_name);
    if (rate_cell)
        return gnc_price_cell_get_value (rate_cell);

    /* Uhh, just return '1' */
    return gnc_numeric_create (100, 100);
}
Esempio n. 13
0
static void
check_reduce (void)
{
    gnc_numeric one, rone;
    gnc_numeric four, rfour;
    gnc_numeric val, rval;
    /* Check common factor elimination (needed for equality checks) */
    one = gnc_numeric_create (1, 1);
    rone = gnc_numeric_create (1000000, 1000000);
    rone = gnc_numeric_reduce (rone);
    do_test (gnc_numeric_eq(one, rone), "reduce to one");

    four = gnc_numeric_create (4, 1);
    rfour = gnc_numeric_create (480, 120);
    rfour = gnc_numeric_reduce (rfour);
    do_test (gnc_numeric_eq(four, rfour), "reduce to four");

    val = gnc_numeric_create(10023234LL, 334216654LL);
    rval = gnc_numeric_reduce (val);
    check_unary_op (gnc_numeric_eq,
                    gnc_numeric_create (5011617, 167108327),
                    rval,
                    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 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 got %s = reduce(%s)");
}
Esempio n. 14
0
/* Get the rate from the price db */
static gnc_numeric
gtu_sr_get_rate_from_db (gnc_commodity *from, gnc_commodity *to)
{
    GNCPrice *prc;
    gnc_numeric rate_split;
    gboolean have_rate = FALSE;
    QofBook *book = gnc_get_current_book ();

    /* Do we have a rate allready */
    prc = gnc_pricedb_lookup_latest (gnc_pricedb_get_db (book), from, to);
    if (prc)
    {
        rate_split = gnc_price_get_value (prc);
        gnc_price_unref (prc);
        have_rate = TRUE;
    }

    /* Lets try reversing the commodities */
    if (!have_rate)
    {
        prc = gnc_pricedb_lookup_latest (gnc_pricedb_get_db (book), to, from);
        if (prc)
        {
            rate_split = gnc_numeric_div (gnc_numeric_create (100, 100), gnc_price_get_value (prc),
                                 GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);

            gnc_price_unref (prc);
            have_rate = TRUE;
        }
    }

    /* No rate, set to 1/1 */
    if (!have_rate)
        rate_split = gnc_numeric_create (100, 100);

    return rate_split;
}
Esempio n. 15
0
/* Copy the values in the financial_info structure to the GUI */
static void
fi_to_gui(FinCalcDialog *fcd)
{
    const gnc_commodity *commodity;
    static char string[64];
    gnc_numeric total;
    gnc_numeric npp;
    gnc_numeric pmt;
    int i;

    if (fcd == NULL)
        return;

    npp = gnc_numeric_create (fcd->financial_info.npp, 1);

    gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(fcd->amounts[PAYMENT_PERIODS]),
                                npp);
    gnc_amount_edit_set_damount (GNC_AMOUNT_EDIT(fcd->amounts[INTEREST_RATE]),
                                 fcd->financial_info.ir);
    gnc_amount_edit_set_damount (GNC_AMOUNT_EDIT(fcd->amounts[PRESENT_VALUE]),
                                 fcd->financial_info.pv);
    gnc_amount_edit_set_damount (GNC_AMOUNT_EDIT(fcd->amounts[PERIODIC_PAYMENT]),
                                 fcd->financial_info.pmt);
    gnc_amount_edit_set_damount (GNC_AMOUNT_EDIT(fcd->amounts[FUTURE_VALUE]),
                                 -fcd->financial_info.fv);

    pmt = double_to_gnc_numeric (fcd->financial_info.pmt, 100000, GNC_HOW_RND_ROUND_HALF_UP);

    commodity = gnc_default_currency ();

    total = gnc_numeric_mul (npp, pmt, gnc_commodity_get_fraction (commodity),
                             GNC_HOW_RND_ROUND_HALF_UP);

    xaccSPrintAmount (string, total, gnc_default_print_info (FALSE));
    gtk_label_set_text (GTK_LABEL(fcd->payment_total_label), string);

    i = normalize_period(&fcd->financial_info.CF);
    gtk_combo_box_set_active(GTK_COMBO_BOX(fcd->compounding_combo), i);

    i = normalize_period(&fcd->financial_info.PF);
    gtk_combo_box_set_active(GTK_COMBO_BOX(fcd->payment_combo), i);

    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fcd->end_of_period_radio),
                                 !fcd->financial_info.bep);

    gtk_toggle_button_set_active
    (GTK_TOGGLE_BUTTON(fcd->discrete_compounding_radio),
     fcd->financial_info.disc);
}
Esempio n. 16
0
/* Get the rate from the price db */
static gnc_numeric
gtu_sr_get_rate_from_db (gnc_commodity *from, gnc_commodity *to)
{
    GNCPrice *prc;
    QofBook *book = gnc_get_current_book ();

    prc = gnc_pricedb_lookup_latest (gnc_pricedb_get_db (book), from, to);

    if (!prc)
        return gnc_numeric_create (100, 100);

    if (gnc_commodity_equiv(from, gnc_price_get_currency(prc)))
        return gnc_numeric_invert(gnc_price_get_value(prc));
    return gnc_price_get_value(prc);
}
Esempio n. 17
0
static void
test_numeric_fcn (QofBook *book, const char *message,
                  void (*set) (GncEmployee *, gnc_numeric),
                  gnc_numeric (*get)(const GncEmployee *))
{
    GncEmployee *employee = gncEmployeeCreate (book);
    gnc_numeric num = gnc_numeric_create (17, 1);

    do_test (!gncEmployeeIsDirty (employee), "test if start dirty");
    gncEmployeeBeginEdit (employee);
    set (employee, num);
    do_test (gncEmployeeIsDirty (employee), "test dirty later");
    gncEmployeeCommitEdit (employee);
    do_test (gncEmployeeIsDirty (employee), "test dirty after commit");
    do_test (gnc_numeric_equal (get (employee), num), message);
    gncEmployeeSetActive (employee, FALSE);
    count++;
}
Esempio n. 18
0
static GncSxInstance*
gnc_sx_instance_new(GncSxInstances *parent, GncSxInstanceState state, GDate *date, void *temporal_state, gint sequence_num)
{
    GncSxInstance *rtn = g_new0(GncSxInstance, 1);
    rtn->parent = parent;
    rtn->orig_state = state;
    rtn->state = state;
    g_date_clear(&rtn->date, 1);
    rtn->date = *date;
    rtn->temporal_state = gnc_sx_clone_temporal_state(temporal_state);

    if (! parent->variable_names_parsed)
    {
        parent->variable_names = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)gnc_sx_variable_free);
        gnc_sx_get_variables(parent->sx, parent->variable_names);
        g_hash_table_foreach(parent->variable_names, (GHFunc)_wipe_parsed_sx_var, NULL);
        parent->variable_names_parsed = TRUE;
    }

    rtn->variable_bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)gnc_sx_variable_free);
    g_hash_table_foreach(parent->variable_names, _clone_sx_var_hash_entry, rtn->variable_bindings);

    {
        int instance_i_value;
        gnc_numeric i_num;
        GncSxVariable *as_var;

        instance_i_value = gnc_sx_get_instance_count(rtn->parent->sx, rtn->temporal_state);
        i_num = gnc_numeric_create(instance_i_value, 1);
        as_var = gnc_sx_variable_new_full("i", i_num, FALSE);

        g_hash_table_insert(rtn->variable_bindings, g_strdup("i"), as_var);
    }

    return rtn;
}
Esempio n. 19
0
static void
test_numeric_fcn (QofBook *book, const char *message,
                  void (*set) (GncEmployee *, gnc_numeric),
                  gnc_numeric (*get)(const GncEmployee *))
{
    GncEmployee *employee = gncEmployeeCreate (book);
    gnc_numeric num = gnc_numeric_create (17, 1);

    do_test (!gncEmployeeIsDirty (employee), "test if start dirty");
    gncEmployeeBeginEdit (employee);
    set (employee, num);
    /* Employee record should be dirty */
    do_test (gncEmployeeIsDirty (employee), "test dirty later");
    gncEmployeeCommitEdit (employee);
    /* Employee record should be not dirty */
    /* Skip, because will always fail without a backend.
     * It's not possible to load a backend in the engine code
     * without having circular dependencies.
     */
    // do_test (!gncEmployeeIsDirty (employee), "test dirty after commit");
    do_test (gnc_numeric_equal (get (employee), num), message);
    gncEmployeeSetActive (employee, FALSE);
    count++;
}
Esempio n. 20
0
gnc_numeric
gnc_numeric_error(GNCNumericErrorCode error_code)
{
    return gnc_numeric_create(error_code, 0LL);
}
static void
gnc_template_register_save_debcred_cell (BasicCell * cell,
        gpointer save_data,
        gpointer user_data)
{
    SRSaveData *sd = save_data;
    SplitRegister *reg = user_data;
    kvp_frame *kvpf;
    const char *value;
    char *error_loc;
    gnc_numeric new_amount;
    gboolean parse_result;

    g_return_if_fail (gnc_basic_cell_has_name (cell, FDEBT_CELL) ||
                      gnc_basic_cell_has_name (cell, FCRED_CELL));

    if (sd->handled_dc)
        return;

    kvpf = xaccSplitGetSlots (sd->split);

    DEBUG ("kvp_frame before: %s\n", kvp_frame_to_string (kvpf));

    /* amountStr = gnc_numeric_to_string (new_amount); */

    value = gnc_table_layout_get_cell_value (reg->table->layout, FCRED_CELL);
    kvp_frame_set_slot_path (kvpf, kvp_value_new_string (value),
                             GNC_SX_ID,
                             GNC_SX_CREDIT_FORMULA,
                             NULL);

    /* If the value can be parsed into a numeric result (without any
     * further variable definitions), store that numeric value
     * additionally in the kvp. Otherwise store a zero numeric
     * there.*/
    parse_result = gnc_exp_parser_parse_separate_vars(value, &new_amount, &error_loc, NULL);
    if (!parse_result)
    {
        new_amount = gnc_numeric_zero();
    }
    kvp_frame_set_slot_path (kvpf, kvp_value_new_numeric (new_amount),
                             GNC_SX_ID,
                             GNC_SX_CREDIT_NUMERIC,
                             NULL);

    value = gnc_table_layout_get_cell_value (reg->table->layout, FDEBT_CELL);

    kvp_frame_set_slot_path (kvpf,
                             kvp_value_new_string (value),
                             GNC_SX_ID,
                             GNC_SX_DEBIT_FORMULA,
                             NULL);

    /* If the value can be parsed into a numeric result, store that
     * numeric value additionally. See above comment.*/
    parse_result = gnc_exp_parser_parse_separate_vars(value, &new_amount, &error_loc, NULL);
    if (!parse_result)
    {
        new_amount = gnc_numeric_zero();
    }
    kvp_frame_set_slot_path (kvpf, kvp_value_new_numeric (new_amount),
                             GNC_SX_ID,
                             GNC_SX_DEBIT_NUMERIC,
                             NULL);

    DEBUG ("kvp_frame  after: %s\n", kvp_frame_to_string (kvpf));

    /* set the amount to an innocuous value */
    /* Note that this marks the split dirty */
    xaccSplitSetValue (sd->split, gnc_numeric_create (0, 1));

    sd->handled_dc = TRUE;
}
Esempio n. 22
0
/*
 * This is the logic of computing the total for an Entry, so you know
 * what values to put into various Splits or to display in the ledger.
 * In other words, we combine the quantity, unit-price, discount and
 * taxes together, depending on various flags.
 *
 * There are four potental ways to combine these numbers:
 * Discount:     Pre-Tax   Post-Tax
 *   Tax   :     Included  Not-Included
 *
 * The process is relatively simple:
 *
 *  1) compute the agregate price (price*qty)
 *  2) if taxincluded, then back-compute the agregate pre-tax price
 *  3) apply discount and taxes in the appropriate order
 *  4) return the requested results.
 *
 * step 2 can be done with agregate taxes; no need to compute them all
 * unless the caller asked for the tax_value.
 *
 * Note that the returned "value" is such that value + tax == "total
 * to pay," which means in the case of tax-included that the returned
 * "value" may be less than the agregate price, even without a
 * discount.  If you want to display the tax-included value, you need
 * to add the value and taxes together.  In other words, the value is
 * the amount the merchant gets; the taxes are the amount the gov't
 * gets, and the customer pays the sum or value + taxes.
 *
 * The SCU is the denominator to convert the value.
 *
 * The discount return value is just for entertainment -- you may want
 * to let a consumer know how much they saved.
 */
void gncEntryComputeValue (gnc_numeric qty, gnc_numeric price,
                           const GncTaxTable *tax_table, gboolean tax_included,
                           gnc_numeric discount, GncAmountType discount_type,
                           GncDiscountHow discount_how, int SCU,
                           gnc_numeric *value, gnc_numeric *discount_value,
                           GList **tax_value)
{
    gnc_numeric	aggregate;
    gnc_numeric	pretax;
    gnc_numeric	result;
    gnc_numeric	tax;
    gnc_numeric	percent = gnc_numeric_create (100, 1);
    gnc_numeric	tpercent = gnc_numeric_zero ();
    gnc_numeric	tvalue = gnc_numeric_zero ();

    GList * 	entries = gncTaxTableGetEntries (tax_table);
    GList * 	node;

    /* Step 1: compute the aggregate price */

    aggregate = gnc_numeric_mul (qty, price, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);

    /* Step 2: compute the pre-tax aggregate */

    /* First, compute the aggregate tpercent and tvalue numbers */
    for (node = entries; node; node = node->next)
    {
        GncTaxTableEntry *entry = node->data;
        gnc_numeric amount = gncTaxTableEntryGetAmount (entry);

        switch (gncTaxTableEntryGetType (entry))
        {
        case GNC_AMT_TYPE_VALUE:
            tvalue = gnc_numeric_add (tvalue, amount, GNC_DENOM_AUTO,
                                      GNC_HOW_DENOM_LCD);
            break;
        case GNC_AMT_TYPE_PERCENT:
            tpercent = gnc_numeric_add (tpercent, amount, GNC_DENOM_AUTO,
                                        GNC_HOW_DENOM_LCD);
            break;
        default:
            g_warning ("Unknown tax type: %d", gncTaxTableEntryGetType (entry));
        }
    }
    /* now we need to convert from 5% -> .05 */
    tpercent = gnc_numeric_div (tpercent, percent, GNC_DENOM_AUTO,
                                GNC_HOW_DENOM_LCD);

    /* Next, actually compute the pre-tax aggregate value based on the
     * taxincluded flag.
     */
    if (tax_table && tax_included)
    {
        /* Back-compute the pre-tax aggregate value.
         * We know that aggregate = pretax + pretax*tpercent + tvalue, so
         * pretax = (aggregate-tvalue)/(1+tpercent)
         */
        pretax = gnc_numeric_sub (aggregate, tvalue, GNC_DENOM_AUTO,
                                  GNC_HOW_DENOM_LCD);
        pretax = gnc_numeric_div (pretax,
                                  gnc_numeric_add (tpercent,
                                          gnc_numeric_create (1, 1),
                                          GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD),
                                  GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
    }
    else
    {
        pretax = aggregate;
    }

    /* Step 3:  apply discount and taxes in the appropriate order */

    /*
     * There are two ways to apply discounts and taxes.  In one way, you
     * always compute the discount off the pretax number, and compute
     * the taxes off of either the pretax value or "pretax-discount"
     * value.  In the other way, you always compute the tax on "pretax",
     * and compute the discount on either "pretax" or "pretax+taxes".
     *
     * I don't know which is the "correct" way.
     */

    /*
     * Type:	discount	tax
     * PRETAX	pretax		pretax-discount
     * SAMETIME	pretax		pretax
     * POSTTAX	pretax+tax	pretax
     */

    switch (discount_how)
    {
    case GNC_DISC_PRETAX:
    case GNC_DISC_SAMETIME:
        /* compute the discount from pretax */

        if (discount_type == GNC_AMT_TYPE_PERCENT)
        {
            discount = gnc_numeric_div (discount, percent, GNC_DENOM_AUTO,
                                        GNC_HOW_DENOM_LCD);
            discount = gnc_numeric_mul (pretax, discount, GNC_DENOM_AUTO,
                                        GNC_HOW_DENOM_LCD);
        }

        result = gnc_numeric_sub (pretax, discount, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);

        /* Figure out when to apply the tax, pretax or pretax-discount */
        if (discount_how == GNC_DISC_PRETAX)
            pretax = result;
        break;

    case GNC_DISC_POSTTAX:
        /* compute discount on pretax+taxes */

        if (discount_type == GNC_AMT_TYPE_PERCENT)
        {
            gnc_numeric after_tax;

            tax = gnc_numeric_mul (pretax, tpercent, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
            after_tax = gnc_numeric_add (pretax, tax, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
            after_tax = gnc_numeric_add (after_tax, tvalue, GNC_DENOM_AUTO,
                                         GNC_HOW_DENOM_LCD);
            discount = gnc_numeric_div (discount, percent, GNC_DENOM_AUTO,
                                        GNC_HOW_DENOM_LCD);
            discount = gnc_numeric_mul (after_tax, discount, GNC_DENOM_AUTO,
                                        GNC_HOW_DENOM_LCD);
        }

        result = gnc_numeric_sub (pretax, discount, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
        break;

    default:
        g_warning ("unknown DiscountHow value: %d", discount_how);
    }

    /* Step 4:  return the requested results. */

    /* result == amount merchant gets
     * discount == amount of discount
     * need to compute taxes (based on 'pretax') if the caller wants it.
     */

    if (discount_value != NULL)
    {
        if (SCU) discount = gnc_numeric_convert(discount, SCU, GNC_HOW_RND_ROUND);
        *discount_value = discount;
    }

    if (value != NULL)
    {
        if (SCU) result = gnc_numeric_convert(result, SCU, GNC_HOW_RND_ROUND);
        *value = result;
    }

    /* Now... Compute the list of tax values (if the caller wants it) */

    if (tax_value != NULL)
    {
        GList *	taxes = NULL;

        for (node = entries; node; node = node->next)
        {
            GncTaxTableEntry *entry = node->data;
            Account *acc = gncTaxTableEntryGetAccount (entry);
            gnc_numeric amount = gncTaxTableEntryGetAmount (entry);

            g_return_if_fail (acc);

            switch (gncTaxTableEntryGetType (entry))
            {
            case GNC_AMT_TYPE_VALUE:
                if (SCU) amount = gnc_numeric_convert(amount, SCU, GNC_HOW_RND_ROUND);
                taxes = gncAccountValueAdd (taxes, acc, amount);
                break;
            case GNC_AMT_TYPE_PERCENT:
                amount = gnc_numeric_div (amount, percent, GNC_DENOM_AUTO,
                                          GNC_HOW_DENOM_LCD);
                tax = gnc_numeric_mul (pretax, amount, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
                if (SCU) tax = gnc_numeric_convert(tax, SCU, GNC_HOW_RND_ROUND);
                taxes = gncAccountValueAdd (taxes, acc, tax);
                break;
            default:
                break;
            }
        }
        *tax_value = taxes;
    }

    return;
}
Esempio n. 23
0
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");

}
Esempio n. 24
0
static void
check_add_subtract_overflow (void)
{
    int i;

    for (i = 0; i < NREPS; i++)
    {
	/* Div to avoid addition overflows; we're looking for lcd conversion overflows here. */

	int exp_a = rand () % 1000;
	int exp_b = rand () % 1000;
        gint64 bin_deno_a = (exp_a == 0 ? 1 : exp_a);
	gint64 bin_deno_b = (exp_b == 0 ? 1 : exp_b);
/*
	int exp_a = rand () % 11;
	int exp_b = rand () % 11;
	gint64 bin_deno_a = (1 << exp_a);
	gint64 bin_deno_b = (1 << exp_a);
*/
	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;
	GNCNumericErrorCode err;
	gchar *errmsg;

        gnc_numeric ba = gnc_numeric_create(na, bin_deno_a);
        gnc_numeric bb = gnc_numeric_create(nb, bin_deno_b);
        gnc_numeric da = gnc_numeric_create(na, dec_deno_a);
        gnc_numeric db = gnc_numeric_create(nb, dec_deno_b);
	gchar *ba_str = gnc_numeric_to_string (ba);
	gchar *bb_str = gnc_numeric_to_string (bb);
	gchar *da_str = gnc_numeric_to_string (da);
	gchar *db_str = gnc_numeric_to_string (db);


        /* Add */

	result = gnc_numeric_add(ba, bb, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
	err = gnc_numeric_check (result);
	errmsg = g_strdup_printf ("%s + %s raised %s", ba_str, bb_str,
				  gnc_numeric_errorCode_to_string (err));
	do_test (err == 0, errmsg);
	g_free (errmsg);

	result = gnc_numeric_add(da, bb, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
	err = gnc_numeric_check (result);
	errmsg = g_strdup_printf ("%s + %s raised %s", da_str, bb_str,
				  gnc_numeric_errorCode_to_string (err));
	do_test (err == 0, errmsg);
	g_free (errmsg);
	result = gnc_numeric_add(ba, db, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
	err = gnc_numeric_check (result);
	errmsg = g_strdup_printf ("%s + %s raised %s", ba_str, db_str,
				  gnc_numeric_errorCode_to_string (err));
	do_test (err == 0, errmsg);
	g_free (errmsg);

	result = gnc_numeric_add(da, db, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
	err = gnc_numeric_check (result);
	errmsg = g_strdup_printf ("%s + %s raised %s", da_str, db_str,
				  gnc_numeric_errorCode_to_string (err));
	do_test (err == 0, errmsg);
	g_free (errmsg);
        /* Subtract */

	result = gnc_numeric_sub(ba, bb, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
	err = gnc_numeric_check (result);
	errmsg = g_strdup_printf ("%s + %s raised %s", ba_str, bb_str,
				  gnc_numeric_errorCode_to_string (err));
	do_test (err == 0, errmsg);
	g_free (errmsg);

	result = gnc_numeric_sub(da, bb, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
	err = gnc_numeric_check (result);
	errmsg = g_strdup_printf ("%s + %s raised %s", da_str, bb_str,
				  gnc_numeric_errorCode_to_string (err));
	do_test (err == 0, errmsg);
	g_free (errmsg);
	result = gnc_numeric_sub(ba, db, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
	err = gnc_numeric_check (result);
	errmsg = g_strdup_printf ("%s + %s raised %s", ba_str, db_str,
				  gnc_numeric_errorCode_to_string (err));
	do_test (err == 0, errmsg);
	g_free (errmsg);

	result = gnc_numeric_sub(da, db, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
	err = gnc_numeric_check (result);
	errmsg = g_strdup_printf ("%s + %s raised %s", da_str, db_str,
				  gnc_numeric_errorCode_to_string (err));
	do_test (err == 0, errmsg);
	g_free (errmsg);

	g_free (ba_str);
	g_free (bb_str);
	g_free (da_str);
	g_free (db_str);
    }

}
Esempio n. 25
0
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");
    }
}
Esempio n. 26
0
gboolean
gnc_numeric_to_decimal(gnc_numeric *a, guint8 *max_decimal_places)
{
    guint8 decimal_places = 0;
    gnc_numeric converted_val;
    gint64 fraction;

    g_return_val_if_fail(a, FALSE);

    if (gnc_numeric_check(*a) != GNC_ERROR_OK)
        return FALSE;

    converted_val = *a;
    if (converted_val.denom <= 0)
    {
        converted_val = gnc_numeric_convert(converted_val, 1, GNC_HOW_DENOM_EXACT);
        if (gnc_numeric_check(converted_val) != GNC_ERROR_OK)
            return FALSE;
        *a = converted_val;
        if (max_decimal_places)
            *max_decimal_places = decimal_places;
        return TRUE;
    }

    /* Zero is easily converted. */
    if (converted_val.num == 0)
        converted_val.denom = 1;

    fraction = converted_val.denom;
    while (fraction != 1)
    {
        switch (fraction % 10)
        {
        case 0:
            fraction = fraction / 10;
            break;

        case 5:
            converted_val = gnc_numeric_mul(converted_val,
                                            gnc_numeric_create(2, 2),
                                            GNC_DENOM_AUTO,
                                            GNC_HOW_DENOM_EXACT |
                                            GNC_HOW_RND_NEVER);
            if (gnc_numeric_check(converted_val) != GNC_ERROR_OK)
                return FALSE;
            fraction = fraction / 5;
            break;

        case 2:
        case 4:
        case 6:
        case 8:
            converted_val = gnc_numeric_mul(converted_val,
                                            gnc_numeric_create(5, 5),
                                            GNC_DENOM_AUTO,
                                            GNC_HOW_DENOM_EXACT |
                                            GNC_HOW_RND_NEVER);
            if (gnc_numeric_check(converted_val) != GNC_ERROR_OK)
                return FALSE;
            fraction = fraction / 2;
            break;

        default:
            return FALSE;
        }

        decimal_places += 1;
    }

    if (max_decimal_places)
        *max_decimal_places = decimal_places;

    *a = converted_val;

    return TRUE;
}
Esempio n. 27
0
static void
check_rounding (void)
{
    gnc_numeric val;

    val = gnc_numeric_create(7, 16);
    check_unary_op (gnc_numeric_eq,
                    gnc_numeric_create (43, 100),
                    gnc_numeric_convert (val, 100, GNC_HOW_RND_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 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 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 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 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 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 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 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 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 got %s = (%s as 100th's round)");
}
Esempio n. 28
0
static void
check_equality_operator (void)
{
    int i, m;
    gint mult;
    gint64 f, deno, numer;
    gnc_numeric big, rbig;
    gnc_numeric val, mval;
    gnc_numeric bval, rval;
    /* Check equality operator for some large numer/denom values */
    numer = 1 << 30;
    numer <<= 30;   /* we don't trust cpp to compute 1<<60 correctly */
    deno = 1 << 30;
    deno <<= 20;
    rbig = gnc_numeric_create (numer, deno);

    big = gnc_numeric_create (1 << 10, 1);
    do_test (gnc_numeric_equal(big, rbig), "equal to billion");

    big = gnc_numeric_create (1 << 20, 1 << 10);
    do_test (gnc_numeric_equal(big, rbig), "equal to 1<<20/1<<10");

    big = gnc_numeric_create (1 << 30, 1 << 20);
    do_test (gnc_numeric_equal(big, rbig), "equal to 1<<30/1<<20");

    numer = 1 << 30;
    numer <<= 30;   /* we don't trust cpp to compute 1<<60 correctly */
    deno = 1 << 30;
    rbig = gnc_numeric_create (numer, deno);

    big = gnc_numeric_create (1 << 30, 1);
    do_test (gnc_numeric_equal(big, rbig), "equal to 1<<30");

    numer = 1 << 30;
    numer <<= 10;
    big = gnc_numeric_create (numer, 1 << 10);
    do_test (gnc_numeric_equal(big, rbig), "equal to 1<<40/1<<10");

    numer <<= 10;
    big = gnc_numeric_create (numer, 1 << 20);
    do_test (gnc_numeric_equal(big, rbig), "equal to 1<<50/1<<20");

    /* We assume RAND_MAX is less that 1<<32 */
    for (i = 0; i < NREPS; i++)
    {
        deno = rand() / 2;
        mult = rand() / 2;
        numer = rand() / 2;

        /* avoid 0 */
        if (deno == 0 || mult == 0)
        {
            i--;
            continue;
        }

        val = gnc_numeric_create (numer, deno);
        mval = gnc_numeric_create (numer * mult, deno * mult);

        /* The reduced version should be equivalent */
        bval = gnc_numeric_reduce (val);
        rval = gnc_numeric_reduce (mval);
        check_unary_op (gnc_numeric_eq,
                        bval, rval, mval, "expected %s got %s = reduce(%s)");

        /* The unreduced versions should be equal */
        check_unary_op (gnc_numeric_equal,
                        val, mval, mval, "expected %s = %s");

        /* Certain modulo's should be very cleary un-equal; this
         * helps stop funky modulo-64 aliasing in compares that
         * might creep in. */
        mval.denom >>= 1;
        mval.num >>= 1;
        m = 0;
        f = mval.denom;
        while (f % 2 == 0)
        {
            f >>= 1;
            m++;
        }
        if (1 < m)
        {
            gint64 nn = 1 << (32 - m);
            nn <<= 32;
            nn += mval.num;
            val = gnc_numeric_create (2 * nn, 2 * mval.denom);
            check_unary_op (gnc_numeric_unequal,
                            val, mval, mval, "expected unequality %s != %s");

        }
    }
}
void
gnc_customer_window_ok_cb (GtkWidget *widget, gpointer data)
{
    CustomerWindow *cw = data;
    gnc_numeric min, max;
    gchar *string;

    /* Check for valid company name */
    if (check_entry_nonempty (cw->dialog, cw->company_entry,
                              _("You must enter a company name. "
                                "If this customer is an individual (and not a company) "
                                "you should enter the same value for:\nIdentification "
                                "- Company Name, and\nPayment Address - Name.")))
        return;

    /* Make sure we have an address */
    if (check_entry_nonempty (cw->dialog, cw->addr1_entry, NULL) &&
            check_entry_nonempty (cw->dialog, cw->addr2_entry, NULL) &&
            check_entry_nonempty (cw->dialog, cw->addr3_entry, NULL) &&
            check_entry_nonempty (cw->dialog, cw->addr4_entry, NULL))
    {
        const char *msg = _("You must enter a billing address.");
        gnc_error_dialog (cw->dialog, "%s", msg);
        return;
    }

    /* Verify terms, discount, and credit are valid (or empty) */
    min = gnc_numeric_zero ();
    max = gnc_numeric_create (100, 1);

    if (check_edit_amount (cw->dialog, cw->discount_amount, &min, &max,
                           _("Discount percentage must be between 0-100 "
                             "or you must leave it blank.")))
        return;

    if (check_edit_amount (cw->dialog, cw->credit_amount, &min, NULL,
                           _("Credit must be a positive amount or "
                             "you must leave it blank.")))
        return;

    /* Set the customer id if one has not been chosen */
    if (g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (cw->id_entry)), "") == 0)
    {
        string = gncCustomerNextID (cw->book);
        gtk_entry_set_text (GTK_ENTRY (cw->id_entry), string);
        g_free(string);
    }

    /* Now save it off */
    {
        GncCustomer *customer = cw_get_customer (cw);
        if (customer)
        {
            gnc_ui_to_customer (cw, customer);
        }
        cw->created_customer = customer;
        cw->customer_guid = *guid_null ();
    }

    gnc_close_gui_component (cw->component_id);
}
Esempio n. 30
0
void
gnc_tree_util_split_reg_save_amount_values (GncTreeViewSplitReg *view, Transaction *trans, Split *split, gnc_numeric input)
{
    GncTreeModelSplitReg *model;
    Account *acc;
    gnc_numeric new_amount, convrate, amtconv, value;
    gnc_commodity *curr, *reg_com, *xfer_com;
    Account *xfer_acc;

    ENTER("View is %p, trans is %p, split is %p, input is %s", view, trans, split, gnc_numeric_to_string (input));

    model = gnc_tree_view_split_reg_get_model_from_view (view);

    new_amount = input;

    acc = gnc_tree_model_split_reg_get_anchor (model);

    xfer_acc = xaccSplitGetAccount (split);
    xfer_com = xaccAccountGetCommodity (xfer_acc);
    reg_com = xaccAccountGetCommodity (acc);
    curr = xaccTransGetCurrency (trans);

    if (!xaccTransGetRateForCommodity (trans, reg_com, NULL, &convrate))
        convrate = gnc_numeric_create (100, 100);

    amtconv = convrate;

    if (gnc_tree_util_split_reg_needs_conv_rate (view, trans, acc))
    {

        /* If we are in an expanded register and the xfer_acc->comm !=
        * reg_acc->comm then we need to compute the convrate here.
        * Otherwise, we _can_ use the rate_cell!
        */
        if (gnc_commodity_equal (reg_com, xfer_com))
            amtconv = xaccTransGetAccountConvRate (trans, acc);
    }

    if (xaccTransUseTradingAccounts (trans))
    {
        /* Using currency accounts, the amount is probably really the
           amount and not the value. */
        gboolean is_amount;

        if (model->type == STOCK_REGISTER2 ||
                model->type == CURRENCY_REGISTER2 ||
                model->type == PORTFOLIO_LEDGER2)
        {
            if (xaccAccountIsPriced (xfer_acc) ||
                    !gnc_commodity_is_iso (xaccAccountGetCommodity (xfer_acc)))
                is_amount = FALSE;
            else
                is_amount = TRUE;
        }
        else
        {
            is_amount = TRUE;
        }

        if (is_amount)
        {
            xaccSplitSetAmount (split, new_amount);
            if (gnc_tree_util_split_reg_needs_amount (view, split))
            {
                value = gnc_numeric_div (new_amount, amtconv,
                                        gnc_commodity_get_fraction (curr),
                                        GNC_HOW_RND_ROUND_HALF_UP);
                xaccSplitSetValue (split, value);
            }
            else
                xaccSplitSetValue (split, new_amount);
        }
        else
        {
            xaccSplitSetValue (split, new_amount);
        }
        LEAVE(" ");
        return;
    }

    /* How to interpret new_amount depends on our view of this
     * transaction.  If we're sitting in an account with the same
     * commodity as the transaction, then we can set the Value and then
     * compute the amount.  Otherwise we are setting the "converted
     * value".  This means we need to convert new_amount to the actual
     * 'value' by dividing by the convrate in order to set the value.
     */

    /* Now compute/set the split value.  Amount is in the register
     * currency but we need to convert to the txn currency.
     */
    if (gnc_tree_util_split_reg_needs_conv_rate (view, trans, acc))
    {
        /* convert the amount to the Value ... */
        value = gnc_numeric_div (new_amount, amtconv,
                                 gnc_commodity_get_fraction (curr),
                                 GNC_HOW_RND_ROUND_HALF_UP);
        xaccSplitSetValue (split, value);
    }
    else
    {
        xaccSplitSetValue (split, new_amount);
    }

    /* Now re-compute the Amount from the Value.  We may need to convert
     * from the Value back to the amount here using the convrate from
     * earlier.
     */
    value = xaccSplitGetValue (split);

    if (gnc_tree_util_split_reg_needs_amount (view, split))
    {
        acc = xaccSplitGetAccount (split);
        new_amount = gnc_numeric_mul (value, convrate,
                                      xaccAccountGetCommoditySCU (acc),
                                      GNC_HOW_RND_ROUND_HALF_UP);
        xaccSplitSetAmount (split, new_amount);
    }
    else
    {
        xaccSplitSetAmount (split, value);
    }
    LEAVE(" ");
}