mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
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:
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 ---------------------- */
|
||||
|
||||
Reference in New Issue
Block a user