Commit 07999d52 authored by Morten Welinder's avatar Morten Welinder Committed by Morten Welinder

Handle integer operations more carefully with respect to overflow.

1999-08-02  Morten Welinder  <terra@diku.dk>

	* src/expr.c (eval_expr_real): Handle integer operations more
 	carefully with respect to overflow.

	* src/cell.c (cell_cleanout): Don't unlink unless there is a sheet
 	to unlink from.

	* src/collect.c (float_range_function2): Actually call the right
 	function.
	(collect_floats_value): Fix type of result.

	* src/mathfunc.c (range_rsq_pop, range_rsq_est): New functions.

	* src/fn-stat.c (gnumeric_pearson): Simplify.
	(gnumeric_rsq): Simplify.
parent 288457b0
1999-08-02 Morten Welinder <terra@diku.dk>
* src/expr.c (eval_expr_real): Handle integer operations more
carefully with respect to overflow.
* src/cell.c (cell_cleanout): Don't unlink unless there is a sheet
to unlink from.
* src/collect.c (float_range_function2): Actually call the right
function.
(collect_floats_value): Fix type of result.
* src/mathfunc.c (range_rsq_pop, range_rsq_est): New functions.
* src/fn-stat.c (gnumeric_pearson): Simplify.
(gnumeric_rsq): Simplify.
1999-08-02 Jody Goldberg <jgoldberg@home.com>
* src/fn-information.c (gnumeric_n) : Fix boolean support.
......@@ -5,11 +22,18 @@
* src/corba-sheet.c: Correct previous typo.
1999-08-02 Elliot Lee <sopwith@redhat.com>
* gnumeric.spec.in: Fix the .spec file to include correct documentation pieces.
* gnumeric.spec.in: Fix the .spec file to include correct
documentation pieces.
* doc/C/Makefile.am: Work with builddir != srcdir
* plugins/lotus-123/Makefile.am: boot.h not needed. lotus-types.h is.
* plugins/xbase/Makefile.am: boot.h not needed.
* po/Makefile.in.in: v3
* src/corba-sheet.c: Use a compilable thing for error string.
1999-08-02 Morten Welinder <terra@diku.dk>
......
1999-08-02 Morten Welinder <terra@diku.dk>
* src/expr.c (eval_expr_real): Handle integer operations more
carefully with respect to overflow.
* src/cell.c (cell_cleanout): Don't unlink unless there is a sheet
to unlink from.
* src/collect.c (float_range_function2): Actually call the right
function.
(collect_floats_value): Fix type of result.
* src/mathfunc.c (range_rsq_pop, range_rsq_est): New functions.
* src/fn-stat.c (gnumeric_pearson): Simplify.
(gnumeric_rsq): Simplify.
1999-08-02 Jody Goldberg <jgoldberg@home.com>
* src/fn-information.c (gnumeric_n) : Fix boolean support.
......@@ -5,11 +22,18 @@
* src/corba-sheet.c: Correct previous typo.
1999-08-02 Elliot Lee <sopwith@redhat.com>
* gnumeric.spec.in: Fix the .spec file to include correct documentation pieces.
* gnumeric.spec.in: Fix the .spec file to include correct
documentation pieces.
* doc/C/Makefile.am: Work with builddir != srcdir
* plugins/lotus-123/Makefile.am: boot.h not needed. lotus-types.h is.
* plugins/xbase/Makefile.am: boot.h not needed.
* po/Makefile.in.in: v3
* src/corba-sheet.c: Use a compilable thing for error string.
1999-08-02 Morten Welinder <terra@diku.dk>
......
......@@ -339,42 +339,6 @@ static char *help_correl = {
"@SEEALSO=COVAR,FISHER,FISHERINV")
};
typedef struct {
guint32 num;
int count;
GSList *array1;
GSList *array2;
float_t sum1;
float_t sum2;
float_t sqrsum1;
float_t sqrsum2;
} stat_correl_t;
static Value *
callback_function_correl (const EvalPosition *ep, Value *value, void *closure)
{
stat_correl_t *mm = closure;
float_t x, *p;
if (!VALUE_IS_NUMBER (value))
return NULL;
p = g_new (float_t, 1);
*p = x = value_get_as_float (value);
if (mm->num < mm->count){
mm->array1 = g_slist_append (mm->array1, p);
mm->sum1 += x;
mm->sqrsum1 += x * x;
} else {
mm->array2 = g_slist_append (mm->array2, p);
mm->sum2 += x;
mm->sqrsum2 += x * x;
}
mm->num++;
return NULL;
}
static Value *
gnumeric_correl (FunctionEvalInfo *ei, Value **argv)
{
......@@ -1907,65 +1871,12 @@ static char *help_pearson = {
};
static Value *
gnumeric_pearson (FunctionEvalInfo *ei, GList *expr_node_list)
gnumeric_pearson (FunctionEvalInfo *ei, Value **argv)
{
stat_correl_t pr;
float_t sum;
int count;
GSList *list1, *list2;
Value *vtmp;
vtmp = gnumeric_count (ei, expr_node_list);
if (!vtmp)
return NULL;
count = value_get_as_int (vtmp);
value_release (vtmp);
if (count % 2 > 0)
return value_new_error (&ei->pos, gnumeric_err_NUM);
pr.count = count / 2;
pr.num = 0;
pr.sum1 = 0.0;
pr.sum2 = 0.0;
pr.sqrsum1 = 0.0;
pr.sqrsum2 = 0.0;
pr.array1 = NULL;
pr.array2 = NULL;
/* FIXME what about blanks ? */
function_iterate_argument_values (&ei->pos, callback_function_correl,
&pr, expr_node_list, TRUE);
list1 = pr.array1;
list2 = pr.array2;
sum = 0.0;
while (list1 != NULL && list2 != NULL){
float_t *x, *y;
x = list1->data;
y = list2->data;
sum += *x * *y;
g_free(x);
g_free(y);
list1 = list1->next;
list2 = list2->next;
}
g_slist_free(pr.array1);
g_slist_free(pr.array2);
#if 0
if (error_message_is_set (ei->error))
return NULL;
#endif
return value_new_float (((pr.count*sum - pr.sum1*pr.sum2)) /
sqrt((pr.count*pr.sqrsum1 - pr.sum1*pr.sum1) *
(pr.count*pr.sqrsum2 - pr.sum2*pr.sum2)));
return gnumeric_correl (ei, argv);
}
static char *help_rsq = {
N_("@FUNCTION=RSQ\n"
"@SYNTAX=RSQ(array1,array2)\n"
......@@ -1981,68 +1892,16 @@ static char *help_rsq = {
};
static Value *
gnumeric_rsq (FunctionEvalInfo *ei, GList *expr_node_list)
gnumeric_rsq (FunctionEvalInfo *ei, Value **argv)
{
stat_correl_t pr;
float_t sum, r;
int count;
GSList *list1, *list2;
Value *vtmp;
vtmp = gnumeric_count (ei, expr_node_list);
if (!vtmp)
return NULL;
count = value_get_as_int (vtmp);
value_release (vtmp);
if (count % 2 > 0)
return value_new_error (&ei->pos, gnumeric_err_NUM);
/* FIXME: what about count == 0? */
pr.count = count / 2;
pr.num = 0;
pr.sum1 = 0.0;
pr.sum2 = 0.0;
pr.sqrsum1 = 0.0;
pr.sqrsum2 = 0.0;
pr.array1 = NULL;
pr.array2 = NULL;
/* FIXME what about blanks ? */
function_iterate_argument_values (&ei->pos, callback_function_correl,
&pr, expr_node_list, TRUE);
list1 = pr.array1;
list2 = pr.array2;
sum = 0.0;
while (list1 != NULL && list2 != NULL){
float_t *x, *y;
x = list1->data;
y = list2->data;
sum += *x * *y;
g_free(x);
g_free(y);
list1 = list1->next;
list2 = list2->next;
}
g_slist_free(pr.array1);
g_slist_free(pr.array2);
#if 0
if (error_message_is_set (ei->error))
return NULL;
#endif
r = (((pr.count*sum - pr.sum1*pr.sum2)) /
sqrt((pr.count*pr.sqrsum1 - pr.sum1*pr.sum1) *
(pr.count*pr.sqrsum2 - pr.sum2*pr.sum2)));
return value_new_float (r * r);
return float_range_function2 (argv[0], argv[1],
ei,
range_rsq_pop,
COLLECT_IGNORE_STRINGS | COLLECT_IGNORE_BOOLS,
gnumeric_err_VALUE);
}
static char *help_median = {
N_("@FUNCTION=MEDIAN\n"
"@SYNTAX=MEDIAN(n1, n2, ...)\n"
......@@ -3612,13 +3471,13 @@ void stat_functions_init()
gnumeric_normsinv);
function_add_args (cat, "percentrank", "Af|f", "array,x,significance",
&help_percentrank, gnumeric_percentrank);
function_add_nodes (cat, "pearson", 0, "", &help_pearson,
function_add_args (cat, "pearson", "AA", "array1,array2", &help_pearson,
gnumeric_pearson);
function_add_args (cat, "prob", "AAf|f", "x_range,prob_range,lower_limit,upper_limit",
&help_prob, gnumeric_prob);
function_add_args (cat, "rank", "fr|f", "", &help_rank,
gnumeric_rank);
function_add_nodes (cat, "rsq", 0, "", &help_rsq,
function_add_args (cat, "rsq", "AA", "array1,array2", &help_rsq,
gnumeric_rsq);
function_add_nodes (cat, "skew", 0, "", &help_skew,
gnumeric_skew);
......
......@@ -52,7 +52,9 @@ static void
cell_cleanout (Cell *cell)
{
if (cell->parsed_node){
sheet_cell_formula_unlink (cell);
/* Clipboard cells, e.g., are not attached to a sheet. */
if (cell->sheet)
sheet_cell_formula_unlink (cell);
expr_tree_unref (cell->parsed_node);
cell->parsed_node = NULL;
}
......
......@@ -132,7 +132,7 @@ collect_floats_value (Value *val, const EvalPosition *ep, CollectFlags flags,
{
GList *exprlist;
ExprTree *expr_val;
Value *res;
float_t *res;
expr_val = expr_tree_new_constant (value_duplicate (val));
exprlist = g_list_prepend (NULL, expr_val);
......@@ -195,7 +195,7 @@ float_range_function2 (Value *val0, Value *val1, FunctionEvalInfo *ei,
else {
float_t fres;
if (range_correl_pop (vals0, vals1, n0, &fres))
if (func (vals0, vals1, n0, &fres))
res = value_new_error (&ei->pos, func_error);
else
res = value_new_float (fres);
......
......@@ -906,47 +906,61 @@ eval_expr_real (FunctionEvalInfo *s, ExprTree const *tree)
if (a->type != VALUE_FLOAT && b->type != VALUE_FLOAT){
int ia = value_get_as_int (a);
int ib = value_get_as_int (b);
double dres;
int ires;
value_release (a);
value_release (b);
/* FIXME: we could use simple (cheap) heuristics to
catch most cases where overflow will not happen. */
switch (tree->oper){
case OPER_ADD:
dres = (double)ia + (double)ib;
ires = (int)dres;
if (dres == ires)
return value_new_int (ires);
else
return value_new_float ((float_t) dres);
case OPER_SUB:
case OPER_ADD: {
int sum;
if (tree->oper == OPER_SUB)
ib = -ib;
sum = ia + ib;
if ((ia > 0) && (ib > 0)){
return (sum < ia)
? value_new_float((double)ia + ib)
: value_new_int(sum);
} else if ((ia < 0) && (ib < 0)){
return (sum > ia)
? value_new_float((double)ia + ib)
: value_new_int(sum);
}
return value_new_int(sum);
}
dres = (double)ia - (double)ib;
ires = (int)dres;
if (dres == ires)
return value_new_int (ires);
else
return value_new_float ((float_t) dres);
case OPER_MULT:
return value_new_int(ia * ib);
dres = (double)ia * (double)ib;
ires = (int)dres;
if (dres == ires)
return value_new_int (ires);
else
return value_new_float ((float_t) dres);
case OPER_DIV:
return (ib == 0)
? value_new_error (&s->pos,
gnumeric_err_DIV0)
: value_new_float(ia / (float_t)ib);
if (ib == 0)
return value_new_error (&s->pos, gnumeric_err_DIV0);
dres = (double)ia / (double)ib;
ires = (int)dres;
if (dres == ires)
return value_new_int (ires);
else
return value_new_float ((float_t) dres);
case OPER_EXP:
if (ia == 0)
return value_new_error (&s->pos,
gnumeric_err_NUM);
return value_new_int(pow (ia, ib));
if (ia == 0 && ib < 0)
return value_new_error (&s->pos, gnumeric_err_NUM);
dres = pow ((double)ia, (double)ib);
ires = (int)dres;
if (dres == ires)
return value_new_int (ires);
else
return value_new_float ((float_t) dres);
default:
break;
abort ();
}
} else {
float_t const va = value_get_as_float(a);
......
......@@ -339,42 +339,6 @@ static char *help_correl = {
"@SEEALSO=COVAR,FISHER,FISHERINV")
};
typedef struct {
guint32 num;
int count;
GSList *array1;
GSList *array2;
float_t sum1;
float_t sum2;
float_t sqrsum1;
float_t sqrsum2;
} stat_correl_t;
static Value *
callback_function_correl (const EvalPosition *ep, Value *value, void *closure)
{
stat_correl_t *mm = closure;
float_t x, *p;
if (!VALUE_IS_NUMBER (value))
return NULL;
p = g_new (float_t, 1);
*p = x = value_get_as_float (value);
if (mm->num < mm->count){
mm->array1 = g_slist_append (mm->array1, p);
mm->sum1 += x;
mm->sqrsum1 += x * x;
} else {
mm->array2 = g_slist_append (mm->array2, p);
mm->sum2 += x;
mm->sqrsum2 += x * x;
}
mm->num++;
return NULL;
}
static Value *
gnumeric_correl (FunctionEvalInfo *ei, Value **argv)
{
......@@ -1907,65 +1871,12 @@ static char *help_pearson = {
};
static Value *
gnumeric_pearson (FunctionEvalInfo *ei, GList *expr_node_list)
gnumeric_pearson (FunctionEvalInfo *ei, Value **argv)
{
stat_correl_t pr;
float_t sum;
int count;
GSList *list1, *list2;
Value *vtmp;
vtmp = gnumeric_count (ei, expr_node_list);
if (!vtmp)
return NULL;
count = value_get_as_int (vtmp);
value_release (vtmp);
if (count % 2 > 0)
return value_new_error (&ei->pos, gnumeric_err_NUM);
pr.count = count / 2;
pr.num = 0;
pr.sum1 = 0.0;
pr.sum2 = 0.0;
pr.sqrsum1 = 0.0;
pr.sqrsum2 = 0.0;
pr.array1 = NULL;
pr.array2 = NULL;
/* FIXME what about blanks ? */
function_iterate_argument_values (&ei->pos, callback_function_correl,
&pr, expr_node_list, TRUE);
list1 = pr.array1;
list2 = pr.array2;
sum = 0.0;
while (list1 != NULL && list2 != NULL){
float_t *x, *y;
x = list1->data;
y = list2->data;
sum += *x * *y;
g_free(x);
g_free(y);
list1 = list1->next;
list2 = list2->next;
}
g_slist_free(pr.array1);
g_slist_free(pr.array2);
#if 0
if (error_message_is_set (ei->error))
return NULL;
#endif
return value_new_float (((pr.count*sum - pr.sum1*pr.sum2)) /
sqrt((pr.count*pr.sqrsum1 - pr.sum1*pr.sum1) *
(pr.count*pr.sqrsum2 - pr.sum2*pr.sum2)));
return gnumeric_correl (ei, argv);
}
static char *help_rsq = {
N_("@FUNCTION=RSQ\n"
"@SYNTAX=RSQ(array1,array2)\n"
......@@ -1981,68 +1892,16 @@ static char *help_rsq = {
};
static Value *
gnumeric_rsq (FunctionEvalInfo *ei, GList *expr_node_list)
gnumeric_rsq (FunctionEvalInfo *ei, Value **argv)
{
stat_correl_t pr;
float_t sum, r;
int count;
GSList *list1, *list2;
Value *vtmp;
vtmp = gnumeric_count (ei, expr_node_list);
if (!vtmp)
return NULL;
count = value_get_as_int (vtmp);
value_release (vtmp);
if (count % 2 > 0)
return value_new_error (&ei->pos, gnumeric_err_NUM);
/* FIXME: what about count == 0? */
pr.count = count / 2;
pr.num = 0;
pr.sum1 = 0.0;
pr.sum2 = 0.0;
pr.sqrsum1 = 0.0;
pr.sqrsum2 = 0.0;
pr.array1 = NULL;
pr.array2 = NULL;
/* FIXME what about blanks ? */
function_iterate_argument_values (&ei->pos, callback_function_correl,
&pr, expr_node_list, TRUE);
list1 = pr.array1;
list2 = pr.array2;
sum = 0.0;
while (list1 != NULL && list2 != NULL){
float_t *x, *y;
x = list1->data;
y = list2->data;
sum += *x * *y;
g_free(x);
g_free(y);
list1 = list1->next;
list2 = list2->next;
}
g_slist_free(pr.array1);
g_slist_free(pr.array2);
#if 0
if (error_message_is_set (ei->error))
return NULL;
#endif
r = (((pr.count*sum - pr.sum1*pr.sum2)) /
sqrt((pr.count*pr.sqrsum1 - pr.sum1*pr.sum1) *
(pr.count*pr.sqrsum2 - pr.sum2*pr.sum2)));
return value_new_float (r * r);
return float_range_function2 (argv[0], argv[1],
ei,
range_rsq_pop,
COLLECT_IGNORE_STRINGS | COLLECT_IGNORE_BOOLS,
gnumeric_err_VALUE);
}
static char *help_median = {
N_("@FUNCTION=MEDIAN\n"
"@SYNTAX=MEDIAN(n1, n2, ...)\n"
......@@ -3612,13 +3471,13 @@ void stat_functions_init()
gnumeric_normsinv);
function_add_args (cat, "percentrank", "Af|f", "array,x,significance",
&help_percentrank, gnumeric_percentrank);
function_add_nodes (cat, "pearson", 0, "", &help_pearson,
function_add_args (cat, "pearson", "AA", "array1,array2", &help_pearson,
gnumeric_pearson);
function_add_args (cat, "prob", "AAf|f", "x_range,prob_range,lower_limit,upper_limit",
&help_prob, gnumeric_prob);
function_add_args (cat, "rank", "fr|f", "", &help_rank,
gnumeric_rank);
function_add_nodes (cat, "rsq", 0, "", &help_rsq,
function_add_args (cat, "rsq", "AA", "array1,array2", &help_rsq,
gnumeric_rsq);
function_add_nodes (cat, "skew", 0, "", &help_skew,
gnumeric_skew);
......
......@@ -339,42 +339,6 @@ static char *help_correl = {
"@SEEALSO=COVAR,FISHER,FISHERINV")
};
typedef struct {
guint32 num;
int count;
GSList *array1;
GSList *array2;
float_t sum1;
float_t sum2;
float_t sqrsum1;
float_t sqrsum2;
} stat_correl_t;
static Value *
callback_function_correl (const EvalPosition *ep, Value *value, void *closure)
{
stat_correl_t *mm = closure;
float_t x, *p;
if (!VALUE_IS_NUMBER (value))
return NULL;
p = g_new (float_t, 1);
*p = x = value_get_as_float (value);
if (mm->num < mm->count){
mm->array1 = g_slist_append (mm->array1, p);
mm->sum1 += x;
mm->sqrsum1 += x * x;
} else {
mm->array2 = g_slist_append (mm->array2, p);
mm->sum2 += x;
mm->sqrsum2 += x * x;
}
mm->num++;
return NULL;
}
static Value *
gnumeric_correl (FunctionEvalInfo *ei, Value **argv)
{
......@@ -1907,65 +1871,12 @@ static char *help_pearson = {
};
static Value *
gnumeric_pearson (FunctionEvalInfo *ei, GList *expr_node_list)
gnumeric_pearson (FunctionEvalInfo *ei, Value **argv)
{
stat_correl_t pr;
float_t sum;
int count;
GSList *list1, *list2;
Value *vtmp;
vtmp = gnumeric_count (ei, expr_node_list);
if (!vtmp)
return NULL;
count = value_get_as_int (vtmp);
value_release (vtmp);
if (count % 2 > 0)
return value_new_error (&ei->pos, gnumeric_err_NUM);
pr.count = count / 2;
pr.num = 0;
pr.sum1 = 0.0;
pr.sum2 = 0.0;
pr.sqrsum1 = 0.0;
pr.sqrsum2 = 0.0;
pr.array1 = NULL;
pr.array2 = NULL;
/* FIXME what about blanks ? */
function_iterate_argument_values (&ei->pos, callback_function_correl,