Convert parser to use gnc_numerics.

Fix bug in gnc_numeric_reduce.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@3093 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Dave Peticolas
2000-10-30 10:46:46 +00:00
parent 97de3f4897
commit b12e1d6675
8 changed files with 95 additions and 42 deletions

View File

@@ -1,3 +1,11 @@
2000-10-30 Dave Peticolas <dave@krondo.com>
* src/gnc-exp-parser.c: modify to use gnc_numerics instead of
doubles.
* src/engine/gnc-numeric.c: special case num == 0 to prevent
divide by zero exception.
2000-10-27 Dave Peticolas <dave@krondo.com>
* src/calculation/expression_parser.c: handle (num) as -num.

View File

@@ -688,7 +688,7 @@ gnc_numeric_reduce(gnc_numeric in) {
gint64 denom = in.denom;
int three_count = 0;
gnc_numeric out;
/* the strategy is to eliminate common factors from
* 2 up to 'max', where max is the smaller of the smaller
* part of the fraction and the sqrt of the larger part of
@@ -700,7 +700,10 @@ gnc_numeric_reduce(gnc_numeric in) {
* i.e. 9, 15, 21), thus the three_count stuff. */
/* special case: one side divides evenly by the other */
if((num > denom) && (num % denom == 0)) {
if (num == 0) {
denom = 1;
}
else if((num > denom) && (num % denom == 0)) {
num = num / denom;
denom = 1;
}
@@ -708,9 +711,9 @@ gnc_numeric_reduce(gnc_numeric in) {
denom = denom / num;
num = 1;
}
max_square = (num > denom) ? denom : num;
/* normal case: test 2, then 3, 5, 7, 11, etc.
* (skip multiples of 2 and 3) */
while(current_divisor * current_divisor <= max_square) {
@@ -732,13 +735,13 @@ gnc_numeric_reduce(gnc_numeric in) {
three_count++;
}
}
if((current_divisor > num) ||
(current_divisor > denom)) {
break;
}
}
/* all calculations are done on positive num, since it's not
* well defined what % does for negative values */
out.num = (in.num < 0) ? (- num) : num;

View File

@@ -1349,13 +1349,11 @@ xaccParseAmount (const char * in_str, gboolean monetary, gnc_numeric *result,
}
}
if (is_negative)
numer = -numer;
if (result != NULL)
{
result->num = numer;
result->denom = denom;
*result = gnc_numeric_create (numer, denom);
if (is_negative)
*result = gnc_numeric_neg (*result);
}
if (endstr != NULL)

View File

@@ -35,7 +35,7 @@
typedef struct ParserNum
{
double value;
gnc_numeric value;
} ParserNum;
@@ -65,21 +65,51 @@ gnc_exp_parser_init (void)
while (gh_list_p(alist) && !gh_null_p(alist))
{
char *name;
double value;
SCM assoc;
SCM val_scm;
gnc_numeric value;
gboolean good;
assoc = gh_car (alist);
alist = gh_cdr (alist);
name = gh_scm2newstr(gh_car (assoc), NULL);
if (!gh_pair_p (assoc))
continue;
name = gh_scm2newstr (gh_car (assoc), NULL);
if (name == NULL)
continue;
value = gh_scm2double(gh_cdr (assoc));
val_scm = gh_cdr (assoc);
good = TRUE;
gnc_exp_parser_set_value (name, value);
if (gh_number_p (val_scm))
{
double dvalue;
free(name);
dvalue = gh_scm2double (val_scm);
value = double_to_gnc_numeric (dvalue, 10000, GNC_RND_FLOOR);
}
else if (gh_string_p (val_scm))
{
char *s;
const char *err;
s = gh_scm2newstr (val_scm, NULL);
err = string_to_gnc_numeric (s, &value);
if (err == NULL)
good = FALSE;
free (s);
}
else
good = FALSE;
if (good)
gnc_exp_parser_set_value (name, gnc_numeric_reduce (value));
free (name);
}
}
@@ -98,9 +128,12 @@ binding_cons (gpointer key, gpointer value, gpointer data)
char *name = key;
ParserNum *pnum = value;
SCM *alist_p = data;
char *num_str;
SCM assoc;
assoc = gh_cons (gh_str02scm (name), gh_double2scm (pnum->value));
num_str = gnc_numeric_to_string (gnc_numeric_reduce (pnum->value));
assoc = gh_cons (gh_str02scm (name), gh_str02scm (num_str));
g_free (num_str);
*alist_p = gh_cons (assoc, *alist_p);
}
@@ -182,7 +215,7 @@ gnc_exp_parser_remove_variable_names (GList * variable_names)
}
gboolean
gnc_exp_parser_get_value (const char * variable_name, double *value_p)
gnc_exp_parser_get_value (const char * variable_name, gnc_numeric *value_p)
{
ParserNum *pnum;
@@ -203,7 +236,7 @@ gnc_exp_parser_get_value (const char * variable_name, double *value_p)
}
void
gnc_exp_parser_set_value (const char * variable_name, double value)
gnc_exp_parser_set_value (const char * variable_name, gnc_numeric value)
{
char *key;
ParserNum *pnum;
@@ -293,12 +326,12 @@ trans_numeric(const char *digit_str,
char **rstr)
{
ParserNum *pnum;
double value;
gnc_numeric value;
if (digit_str == NULL)
return NULL;
if (!DxaccParseAmount (digit_str, TRUE, &value, rstr))
if (!xaccParseAmount (digit_str, TRUE, &value, rstr))
return NULL;
pnum = g_new0(ParserNum, 1);
@@ -324,16 +357,20 @@ numeric_ops(char op_sym,
switch (op_sym)
{
case ADD_OP:
result->value = left->value + right->value;
result->value = gnc_numeric_add (left->value, right->value,
GNC_DENOM_AUTO, GNC_DENOM_EXACT);
break;
case SUB_OP:
result->value = left->value - right->value;
result->value = gnc_numeric_sub (left->value, right->value,
GNC_DENOM_AUTO, GNC_DENOM_EXACT);
break;
case DIV_OP:
result->value = left->value / right->value;
result->value = gnc_numeric_div (left->value, right->value,
GNC_DENOM_AUTO, GNC_DENOM_EXACT);
break;
case MUL_OP:
result->value = left->value * right->value;
result->value = gnc_numeric_mul (left->value, right->value,
GNC_DENOM_AUTO, GNC_DENOM_EXACT);
break;
case ASN_OP:
result->value = right->value;
@@ -351,13 +388,13 @@ negate_numeric(void *value)
if (value == NULL)
return NULL;
result->value = -result->value;
result->value = gnc_numeric_neg (result->value);
return result;
}
gboolean
gnc_exp_parser_parse (const char * expression, double *value_p,
gnc_exp_parser_parse (const char * expression, gnc_numeric *value_p,
char **error_loc_p)
{
parser_env_ptr pe;
@@ -390,7 +427,7 @@ gnc_exp_parser_parse (const char * expression, double *value_p,
if (error_loc == NULL)
{
if ((value_p != NULL) && (pnum != NULL))
*value_p = pnum->value;
*value_p = gnc_numeric_reduce (pnum->value);
if (error_loc_p != NULL)
*error_loc_p = NULL;

View File

@@ -24,6 +24,8 @@
#include <glib.h>
#include "gnc-numeric.h"
/* Initialize the expression parser. If this function is not
* called before one of the other parsing routines (other than
@@ -48,11 +50,11 @@ void gnc_exp_parser_remove_variable_names (GList * variable_names);
* and value_p != NULL, return the value in *value_p, otherwise, *value_p
* is unchanged. */
gboolean gnc_exp_parser_get_value (const char * variable_name,
double *value_p);
gnc_numeric *value_p);
/* Set the value of the variable to the given value. If the variable is
* not already defined, it will be after the call. */
void gnc_exp_parser_set_value (const char * variable_name, double value);
void gnc_exp_parser_set_value (const char * variable_name, gnc_numeric value);
/* Parse the given expression using the current variable definitions.
* If the parse was successful, return TRUE and, if value_p is
@@ -61,7 +63,7 @@ void gnc_exp_parser_set_value (const char * variable_name, double value);
* returned and error_loc_p is non-NULL, *error_loc_p is set to the
* character in expression where parsing aborted. If TRUE is returned
* and error_loc_p is non-NULL, *error_loc_p is set to NULL. */
gboolean gnc_exp_parser_parse (const char * expression, double *value_p,
gboolean gnc_exp_parser_parse (const char * expression, gnc_numeric *value_p,
char **error_loc_p);
/* If the last parse returned FALSE, return an error string describing

View File

@@ -247,7 +247,8 @@ gnc_amount_edit_evaluate (GNCAmountEdit *gae)
{
const char *string;
char *error_loc;
double amount;
gnc_numeric amount;
double damount;
gboolean ok;
g_return_val_if_fail(gae != NULL, FALSE);
@@ -264,10 +265,12 @@ gnc_amount_edit_evaluate (GNCAmountEdit *gae)
if (ok)
{
if (!DEQ(amount, gae->amount))
damount = gnc_numeric_to_double (amount);
if (!DEQ(damount, gae->amount))
gtk_signal_emit (GTK_OBJECT (gae), amount_edit_signals [AMOUNT_CHANGED]);
gnc_amount_edit_set_amount (gae, amount);
gnc_amount_edit_set_amount (gae, damount);
return TRUE;
}

View File

@@ -66,13 +66,15 @@ PriceDirect (BasicCell *bcell,
case GDK_KP_Enter:
{
char *error_loc;
double amount;
gnc_numeric amount;
if (!cell->need_to_parse)
return FALSE;
if (gnc_exp_parser_parse(cell->cell.value, &amount, &error_loc))
xaccSetPriceCellValue (cell, amount);
if (gnc_exp_parser_parse(cell->cell.value,
&amount, &error_loc))
xaccSetPriceCellValue (cell,
gnc_numeric_to_double (amount));
else
*cursor_position = error_loc - cell->cell.value;

View File

@@ -138,7 +138,7 @@ PriceParse (PriceCell *cell)
{
const char *newval;
char *oldval;
double amount;
gnc_numeric amount;
if (!cell->need_to_parse)
return;
@@ -148,7 +148,7 @@ PriceParse (PriceCell *cell)
oldval = "";
if (gnc_exp_parser_parse (cell->cell.value, &amount, NULL))
cell->amount = amount;
cell->amount = gnc_numeric_to_double (amount);
else
cell->amount = 0.0;
@@ -375,7 +375,7 @@ static void
PriceSetValue (BasicCell *_cell, const char *str)
{
PriceCell *cell = (PriceCell *) _cell;
double amount;
gnc_numeric amount;
if (str == NULL)
str = "";
@@ -383,7 +383,7 @@ PriceSetValue (BasicCell *_cell, const char *str)
if (*str == '\0')
xaccSetPriceCellValue (cell, 0.0);
else if (gnc_exp_parser_parse (str, &amount, NULL))
xaccSetPriceCellValue (cell, amount);
xaccSetPriceCellValue (cell, gnc_numeric_to_double (amount));
}
/* --------------- end of file ---------------------- */