[gnumeric] fn-stat: modernize code for LINEST and friends.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnumeric] fn-stat: modernize code for LINEST and friends.
- Date: Sat, 12 Jun 2010 01:17:46 +0000 (UTC)
commit 39ca2444149f4ef8a470551ce53bb049d566a98d
Author: Morten Welinder <terra gnome org>
Date: Fri Jun 11 21:16:44 2010 -0400
fn-stat: modernize code for LINEST and friends.
NEWS | 1 +
plugins/fn-stat/ChangeLog | 7 +
plugins/fn-stat/functions.c | 776 +++++++++++++------------------------------
3 files changed, 237 insertions(+), 547 deletions(-)
---
diff --git a/NEWS b/NEWS
index 5866665..b3ece5a 100644
--- a/NEWS
+++ b/NEWS
@@ -31,6 +31,7 @@ Morten:
* Automate win32 help generation.
* Mark a sheet dirty when its tab colour is changed. [#621191]
* Fix SERIESSUM issue.
+ * Modernize code for LINEST, LOGEST, and LOGREG. [#317426]
--------------------------------------------------------------------------
Gnumeric 1.10.5
diff --git a/plugins/fn-stat/ChangeLog b/plugins/fn-stat/ChangeLog
index 35cfbba..dbb0255 100644
--- a/plugins/fn-stat/ChangeLog
+++ b/plugins/fn-stat/ChangeLog
@@ -1,3 +1,10 @@
+2010-06-11 Morten Welinder <terra gnome org>
+
+ * functions.c (gnm_reg_data_collect, gnm_reg_data_free): New
+ functions.
+ (gnumeric_linest, gnumeric_logreg, gnumeric_logest): Simplify
+ using gnm_reg_data_collect. Fixes #317426.
+
2010-06-10 Andreas J. Guelzow <aguelzow pyrshep ca>
* functions.c: remove superfluous spaces, inconsitent periods, etc.
diff --git a/plugins/fn-stat/functions.c b/plugins/fn-stat/functions.c
index 9e04720..14b22ca 100644
--- a/plugins/fn-stat/functions.c
+++ b/plugins/fn-stat/functions.c
@@ -3243,6 +3243,149 @@ gnumeric_frequency (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
/***************************************************************************/
+/* Notes for now, to be incorporated into help when it actually works:
+ *
+ * Entered as linest(Yrange, [Xrange, [Intercept, [Stat]]]). Intercept and Stat
+ * work as above. According to playing with Excel, if Yrange is an array, Xrange
+ * must be an array. They claim that you can use semicolons to separate rows in
+ * an array, but I've never gotten that to work. If Yrange is a single column,
+ * every column in the Xrange (which must be a cell range) is interpreted as a
+ * separate variable. Similar for a single row. If Y is a blob, X is interpreted
+ * as a single variable blob. Experiments suggest that multivariable blobs don't work.
+ * Currently everything should be implemented except for inputting arrays. X's must
+ * be contiguous so far as I can tell.
+ */
+
+typedef struct {
+ gnm_float *ys;
+ int n;
+ gnm_float **xss;
+ int dim;
+} GnmRegData;
+
+static void
+gnm_reg_data_free (GnmRegData *data)
+{
+ int i;
+
+ g_free (data->ys);
+ for (i = 0; i < data->dim; i++)
+ g_free (data->xss[i]);
+ g_free (data->xss);
+
+ memset (data, 0, sizeof (*data));
+}
+
+static gnm_float *
+gnm_reg_get_var (GnmValue const *xval, int x, int y, int dx, int dy,
+ int n, GnmEvalPos const *ep)
+{
+ gnm_float *res = g_new (gnm_float, n);
+ int i;
+
+ for (i = 0; i < n; i++) {
+ GnmValue const *v = value_area_fetch_x_y (xval, x, y, ep);
+
+ if (!VALUE_IS_FLOAT (v)) {
+ /* Anything else is an error. */
+ g_free (res);
+ return NULL;
+ }
+
+ res[i] = value_get_as_float (v);
+ x += dx;
+ y += dy;
+ }
+
+ return res;
+}
+
+
+
+static GnmValue *
+gnm_reg_data_collect (GnmValue const *yval, GnmValue const *xval,
+ GnmRegData *data, GnmEvalPos const *ep)
+{
+ int yh = value_area_get_height (yval, ep);
+ int yw = value_area_get_width (yval, ep);
+ int ny;
+ GnmValue *result = NULL;
+
+ memset (data, 0, sizeof (data));
+
+ /* Blanks, bools, strings, errors all are forbidden. */
+ data->ys = collect_floats_value (yval, ep, 0,
+ &ny, &result);
+ if (result || ny <= 0)
+ goto error;
+ data->n = ny;
+
+ if (VALUE_IS_EMPTY (xval)) {
+ int i;
+
+ data->dim = 1;
+ data->xss = g_new (gnm_float *, data->dim);
+ data->xss[0] = g_new (gnm_float, ny);
+ for (i = 0; i < ny; i++)
+ data->xss[0][i] = i + 1;
+ } else {
+ int xh = value_area_get_height (xval, ep);
+ int xw = value_area_get_width (xval, ep);
+ int i, nx;
+
+ if (yw == 1) {
+ /* X's columns are the variables. */
+ if (xh != yh)
+ goto ref_error;
+ data->dim = xw;
+ data->xss = g_new0 (gnm_float *, data->dim);
+ for (i = 0; i < data->dim; i++) {
+ data->xss[i] = gnm_reg_get_var
+ (xval, i, 0, 0, +1, xh, ep);
+ if (!data->xss[i])
+ goto error;
+ }
+ } else if (yh == 1) {
+ /* X's rows are the variables. */
+ if (xw != yw)
+ goto ref_error;
+ data->dim = xh;
+ data->xss = g_new0 (gnm_float *, data->dim);
+ for (i = 0; i < data->dim; i++) {
+ data->xss[i] = gnm_reg_get_var
+ (xval, 0, i, +1, 0, xw, ep);
+ if (!data->xss[i])
+ goto error;
+ }
+ } else {
+ if (xh != yh || xw != yw)
+ goto ref_error;
+ data->dim = 1;
+ data->xss = g_new0 (gnm_float *, data->dim);
+ data->xss[0] = collect_floats_value (xval, ep, 0,
+ &nx, &result);
+ if (result)
+ goto error;
+ }
+ }
+
+ return NULL;
+
+ error:
+ value_release (result);
+ /* Always this kind of error. */
+ result = value_new_error_VALUE (ep);
+ gnm_reg_data_free (data);
+ return result;
+
+ ref_error:
+ /* If the areas have the wrong shape, we get #REF! */
+ gnm_reg_data_free (data);
+ return value_new_error_REF (ep);
+}
+
+
+
static GnmFuncHelp const help_linest[] = {
{ GNM_FUNC_HELP_NAME, F_("LINEST:multiple linear regression coefficients and statistics") },
{ GNM_FUNC_HELP_ARG, F_("known_y's:vector of values of dependent variable.") },
@@ -3268,194 +3411,29 @@ static GnmFuncHelp const help_linest[] = {
{ GNM_FUNC_HELP_END }
};
-/* Notes for now, to be incorporated into help when it actually works:
- *
- * Entered as linest(Yrange, [Xrange, [Intercept, [Stat]]]). Intercept and Stat
- * work as above. According to playing with Excel, if Yrange is an array, Xrange
- * must be an array. They claim that you can use semicolons to separate rows in
- * an array, but I've never gotten that to work. If Yrange is a single column,
- * every column in the Xrange (which must be a cell range) is interpreted as a
- * separate variable. Similar for a single row. If Y is a blob, X is interpreted
- * as a single variable blob. Experiments suggest that multivariable blobs don't work.
- * Currently everything should be implemented except for inputting arrays. X's must
- * be contiguous so far as I can tell.
- */
-
static GnmValue *
gnumeric_linest (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
- gnm_float **xss = NULL, *ys = NULL;
- GnmValue *result = NULL;
- int nx, ny, dim, i, ny_exp = 0;
- int xarg = 1;
- gnm_float *linres = NULL;
- gboolean affine, stat, err;
- enum {
- ARRAY = 1,
- SINGLE_COL = 2,
- SINGLE_ROW = 3,
- OTHER = 4
- } ytype;
- gnm_regression_stat_t *extra_stat;
+ GnmRegData data;
+ gnm_regression_stat_t *extra_stat = NULL;
GORegressionResult regres;
+ GnmValue *result;
+ gnm_float *linres = NULL;
+ gboolean affine, withstat;
+ int i, dim;
- extra_stat = gnm_regression_stat_new ();
- dim = 0;
-
- if (argv[0] == NULL || (argv[0]->type != VALUE_ARRAY && argv[0]->type != VALUE_CELLRANGE)){
- goto out; /* Not a valid input for ys */
- }
-
- if (argv[0]->type == VALUE_ARRAY)
- ytype = ARRAY;
- else if (argv[0]->v_range.cell.a.col == argv[0]->v_range.cell.b.col) {
- ny_exp = argv[0]->v_range.cell.b.row - argv[0]->v_range.cell.a.row + 1;
- ytype = SINGLE_COL;
- } else if (argv[0]->v_range.cell.a.row == argv[0]->v_range.cell.b.row) {
- ytype = SINGLE_ROW;
- ny_exp = argv[0]->v_range.cell.b.col - argv[0]->v_range.cell.a.col + 1;
- } else ytype = OTHER;
-
- if (argv[0]->type == VALUE_CELLRANGE)
- ys = collect_floats_value (argv[0], ei->pos,
- COLLECT_IGNORE_STRINGS |
- COLLECT_IGNORE_BOOLS |
- COLLECT_IGNORE_BLANKS,
- &ny, &result);
- else if (argv[0]->type == VALUE_ARRAY){
- ny = 0;
- /*
- * Get ys from array argument argv[0]
- */
- }
-
- if (result || ny < 1)
- goto out;
-
- if (ny != ny_exp) {
- result = value_new_error_NUM (ei->pos);
- goto out;
- }
-
- /* TODO Better error-checking in next statement */
-
- if (argv[1] == NULL || (ytype == ARRAY && argv[1]->type != VALUE_ARRAY) ||
- (ytype != ARRAY && argv[1]->type != VALUE_CELLRANGE)){
- xarg = 0;
- dim = 1;
- xss = g_new (gnm_float *, 1);
- xss[0] = g_new (gnm_float, ny);
- for (nx = 0; nx < ny; nx++)
- xss[0][nx] = nx + 1;
- } else if (ytype == ARRAY){
- /* Get xss from array argument argv[1] */
- nx = 0;
- } else if (ytype == SINGLE_COL){
- GnmValue *copy = value_dup (argv[1]);
- int firstcol = argv[1]->v_range.cell.a.col;
- int lastcol = argv[1]->v_range.cell.b.col;
- if (firstcol > lastcol) {
- int tmp = firstcol;
- firstcol = lastcol;
- lastcol = tmp;
- }
-
- dim = lastcol - firstcol + 1;
- xss = g_new (gnm_float *, dim);
- for (i = firstcol; i <= lastcol; i++){
- copy->v_range.cell.a.col = i;
- copy->v_range.cell.b.col = i;
- xss[i - firstcol] = collect_floats_value (copy, ei->pos,
- COLLECT_IGNORE_STRINGS |
- COLLECT_IGNORE_BOOLS |
- COLLECT_IGNORE_BLANKS,
- &nx, &result);
- if (result){
- value_release (copy);
- dim = i - firstcol; /* How many got allocated before failure*/
- goto out;
- }
- if (nx != ny){
- value_release (copy);
- dim = i - firstcol + 1;
- result = value_new_error_NUM (ei->pos);
- goto out;
- }
- }
- value_release (copy);
- } else if (ytype == SINGLE_ROW){
- GnmValue *copy = value_dup (argv[1]);
- int firstrow = argv[1]->v_range.cell.a.row;
- int lastrow = argv[1]->v_range.cell.b.row;
- if (firstrow > lastrow) {
- int tmp = firstrow;
- firstrow = lastrow;
- lastrow = tmp;
- }
-
- dim = lastrow - firstrow + 1;
- xss = g_new (gnm_float *, dim);
- for (i = firstrow; i <= lastrow; i++){
- copy->v_range.cell.a.row = i;
- copy->v_range.cell.b.row = i;
- xss[i - firstrow] = collect_floats_value (copy, ei->pos,
- COLLECT_IGNORE_STRINGS |
- COLLECT_IGNORE_BOOLS |
- COLLECT_IGNORE_BLANKS,
- &nx, &result);
- if (result){
- value_release (copy);
- dim = i - firstrow; /*How many got allocated before failure*/
- goto out;
- }
- if (nx != ny){
- value_release (copy);
- dim = i - firstrow + 1;
- result = value_new_error_NUM (ei->pos);
- goto out;
- }
- }
- value_release (copy);
- } else { /*Y is none of the above */
- dim = 1;
- xss = g_new (gnm_float *, dim);
- xss[0] = collect_floats_value (argv[1], ei->pos,
- COLLECT_IGNORE_STRINGS |
- COLLECT_IGNORE_BOOLS |
- COLLECT_IGNORE_BLANKS,
- &nx, &result);
- if (result){
- dim = 0;
- goto out;
- }
- if (nx != ny){
- dim = 1;
- result = value_new_error_NUM (ei->pos);
- goto out;
- }
- }
+ result = gnm_reg_data_collect (argv[0], argv[1], &data, ei->pos);
+ if (result)
+ return result;
+ dim = data.dim;
- if (argv[1 + xarg]) {
- affine = value_get_as_bool (argv[1 + xarg], &err);
- if (err) {
- result = value_new_error_VALUE (ei->pos);
- goto out;
- }
- } else
- affine = TRUE;
-
- if (argv[2 + xarg]) {
- stat = value_get_as_bool (argv[2 + xarg], &err);
- if (err) {
- result = value_new_error_VALUE (ei->pos);
- goto out;
- }
- } else
- stat = FALSE;
+ affine = argv[2] ? value_get_as_checked_bool (argv[2]) : TRUE;
+ withstat = argv[3] ? value_get_as_checked_bool (argv[3]) : FALSE;
linres = g_new (gnm_float, dim + 1);
-
- regres = gnm_linear_regression (xss, dim, ys, nx, affine,
+ extra_stat = gnm_regression_stat_new ();
+ regres = gnm_linear_regression (data.xss, dim,
+ data.ys, data.n, affine,
linres, extra_stat);
switch (regres) {
case GO_REG_ok:
@@ -3466,7 +3444,7 @@ gnumeric_linest (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
goto out;
}
- if (stat) {
+ if (withstat) {
result = value_new_array (dim + 1, 5);
value_array_set (result, 0, 2,
@@ -3496,12 +3474,7 @@ gnumeric_linest (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
value_new_float (linres[i + 1]));
out:
- if (xss) {
- for (i = 0; i < dim; i++)
- g_free (xss[i]);
- g_free (xss);
- }
- g_free (ys);
+ gnm_reg_data_free (&data);
g_free (linres);
gnm_regression_stat_destroy (extra_stat);
@@ -3539,7 +3512,7 @@ static GnmFuncHelp const help_logreg[] = {
{ GNM_FUNC_HELP_SEEALSO, "LOGFIT,LINEST,LOGEST"},
{ GNM_FUNC_HELP_END }
};
-/* The following is a copy of "gnumeric_linest" of Gnumeric version 1.1.9
+/* The following is a copy of "gnumeric_linest"
* with "linear_regression" replaced by "logarithmic_regression".
*
* In Excel, this functionality is not available as a function, but only
@@ -3555,174 +3528,30 @@ static GnmFuncHelp const help_logreg[] = {
* But see comment to "gnumeric_linest" for problem with reading more than
* one x-range.
*/
-
static GnmValue *
gnumeric_logreg (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
- gnm_float **xss = NULL, *ys = NULL;
- GnmValue *result = NULL;
- int nx, ny, dim, i;
- int xarg = 1;
- gnm_float *logreg_res = NULL;
- gboolean affine, stat, err;
+ GnmRegData data;
+ gnm_regression_stat_t *extra_stat = NULL;
GORegressionResult regres;
- enum {
- ARRAY = 1,
- SINGLE_COL = 2,
- SINGLE_ROW = 3,
- OTHER = 4
- } ytype;
- gnm_regression_stat_t *extra_stat;
-
- extra_stat = gnm_regression_stat_new ();
- dim = 0;
-
- if (argv[0] == NULL || (argv[0]->type != VALUE_ARRAY && argv[0]->type != VALUE_CELLRANGE)){
- goto out; /* Not a valid input for ys */
- }
-
- if (argv[0]->type == VALUE_ARRAY)
- ytype = ARRAY;
- else if (argv[0]->v_range.cell.a.col == argv[0]->v_range.cell.b.col)
- ytype = SINGLE_COL;
- else if (argv[0]->v_range.cell.a.row == argv[0]->v_range.cell.b.row)
- ytype = SINGLE_ROW;
- else ytype = OTHER;
-
- if (argv[0]->type == VALUE_CELLRANGE) {
- ys = collect_floats_value (argv[0], ei->pos,
- COLLECT_IGNORE_STRINGS |
- COLLECT_IGNORE_BOOLS,
- &ny, &result);
- } else if (argv[0]->type == VALUE_ARRAY) {
- ny = 0;
- /*
- * Get ys from array argument argv[0]
- */
- }
-
- if (result || ny < 1)
- goto out;
-
- /* TODO Better error-checking in next statement */
-
- if (argv[1] == NULL || (ytype == ARRAY && argv[1]->type != VALUE_ARRAY) ||
- (ytype != ARRAY && argv[1]->type != VALUE_CELLRANGE)){
- xarg = 0;
- dim = 1;
- xss = g_new (gnm_float *, 1);
- xss[0] = g_new (gnm_float, ny);
- for (nx = 0; nx < ny; nx++)
- xss[0][nx] = nx + 1;
- } else if (ytype == ARRAY) {
- /* Get xss from array argument argv[1] */
- nx = 0;
- } else if (ytype == SINGLE_COL) {
- GnmValue *copy = value_dup (argv[1]);
- int firstcol = argv[1]->v_range.cell.a.col;
- int lastcol = argv[1]->v_range.cell.b.col;
-
- if (firstcol > lastcol) {
- int tmp = firstcol;
- firstcol = lastcol;
- lastcol = tmp;
- }
-
- dim = lastcol - firstcol + 1;
- xss = g_new (gnm_float *, dim);
- for (i = firstcol; i <= lastcol; i++){
- copy->v_range.cell.a.col = i;
- copy->v_range.cell.b.col = i;
- xss[i - firstcol] = collect_floats_value (copy, ei->pos,
- COLLECT_IGNORE_STRINGS |
- COLLECT_IGNORE_BOOLS,
- &nx, &result);
- if (result){
- value_release (copy);
- dim = i - firstcol; /* How many got allocated before failure*/
- goto out;
- }
- if (nx != ny){
- value_release (copy);
- dim = i - firstcol + 1;
- result = value_new_error_NUM (ei->pos);
- goto out;
- }
- }
- value_release (copy);
- } else if (ytype == SINGLE_ROW) {
- GnmValue *copy = value_dup (argv[1]);
- int firstrow = argv[1]->v_range.cell.a.row;
- int lastrow = argv[1]->v_range.cell.b.row;
-
- if (firstrow > lastrow) {
- int tmp = firstrow;
- firstrow = lastrow;
- lastrow = tmp;
- }
+ GnmValue *result;
+ gnm_float *logres = NULL;
+ gboolean affine, withstat;
+ int i, dim;
- dim = lastrow - firstrow + 1;
- xss = g_new (gnm_float *, dim);
- for (i = firstrow; i <= lastrow; i++){
- copy->v_range.cell.a.row = i;
- copy->v_range.cell.b.row = i;
- xss[i - firstrow] = collect_floats_value (copy, ei->pos,
- COLLECT_IGNORE_STRINGS |
- COLLECT_IGNORE_BOOLS,
- &nx, &result);
- if (result){
- value_release (copy);
- dim = i - firstrow; /*How many got allocated before failure*/
- goto out;
- }
- if (nx != ny){
- value_release (copy);
- dim = i - firstrow + 1;
- result = value_new_error_NUM (ei->pos);
- goto out;
- }
- }
- value_release (copy);
- } else { /*Y is none of the above */
- dim = 1;
- xss = g_new (gnm_float *, dim);
- xss[0] = collect_floats_value (argv[1], ei->pos,
- COLLECT_IGNORE_STRINGS |
- COLLECT_IGNORE_BOOLS,
- &nx, &result);
- if (result){
- dim = 0;
- goto out;
- }
- if (nx != ny){
- dim = 1;
- result = value_new_error_NUM (ei->pos);
- goto out;
- }
- }
-
- if (argv[1 + xarg]) {
- affine = value_get_as_bool (argv[1 + xarg], &err);
- if (err) {
- result = value_new_error_VALUE (ei->pos);
- goto out;
- }
- } else
- affine = TRUE;
-
- if (argv[2 + xarg]) {
- stat = value_get_as_bool (argv[2 + xarg], &err);
- if (err) {
- result = value_new_error_VALUE (ei->pos);
- goto out;
- }
- } else
- stat = FALSE;
+ result = gnm_reg_data_collect (argv[0], argv[1], &data, ei->pos);
+ if (result)
+ return result;
+ dim = data.dim;
- logreg_res = g_new (gnm_float, dim + 1);
+ affine = argv[2] ? value_get_as_checked_bool (argv[2]) : TRUE;
+ withstat = argv[3] ? value_get_as_checked_bool (argv[3]) : FALSE;
- regres = gnm_logarithmic_regression (xss, dim, ys, nx, affine,
- logreg_res, extra_stat);
+ logres = g_new (gnm_float, dim + 1);
+ extra_stat = gnm_regression_stat_new ();
+ regres = gnm_logarithmic_regression (data.xss, dim,
+ data.ys, data.n, affine,
+ logres, extra_stat);
switch (regres) {
case GO_REG_ok:
case GO_REG_near_singular_good:
@@ -3732,7 +3561,7 @@ gnumeric_logreg (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
goto out;
}
- if (stat) {
+ if (withstat) {
result = value_new_array (dim + 1, 5);
value_array_set (result, 0, 2,
@@ -3751,23 +3580,19 @@ gnumeric_logreg (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
value_array_set (result, dim - i - 1, 1,
value_new_float (extra_stat->se[i+affine]));
value_array_set (result, dim, 1,
- value_new_float (extra_stat->se[0]));
+ affine ? value_new_float (extra_stat->se[0])
+ : value_new_error_NA (ei->pos));
} else
result = value_new_array (dim + 1, 1);
- value_array_set (result, dim, 0, value_new_float (logreg_res[0]));
+ value_array_set (result, dim, 0, value_new_float (logres[0]));
for (i = 0; i < dim; i++)
value_array_set (result, dim - i - 1, 0,
- value_new_float (logreg_res[i + 1]));
+ value_new_float (logres[i + 1]));
out:
- if (xss) {
- for (i = 0; i < dim; i++)
- g_free (xss[i]);
- g_free (xss);
- }
- g_free (ys);
- g_free (logreg_res);
+ gnm_reg_data_free (&data);
+ g_free (logres);
gnm_regression_stat_destroy (extra_stat);
return result;
@@ -4010,166 +3835,26 @@ static GnmFuncHelp const help_logest[] = {
static GnmValue *
gnumeric_logest (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
- gnm_float **xss = NULL, *ys = NULL;
- GnmValue *result = NULL;
- int affine, nx, ny, dim, i;
- int xarg = 1;
- gnm_float *expres = NULL;
- gboolean stat, err;
- gnm_regression_stat_t *extra_stat;
+ GnmRegData data;
+ gnm_regression_stat_t *extra_stat = NULL;
GORegressionResult regres;
- enum {
- ARRAY = 1,
- SINGLE_COL = 2,
- SINGLE_ROW = 3,
- OTHER = 4
- } ytype;
+ GnmValue *result;
+ gnm_float *expres = NULL;
+ gboolean affine, withstat;
+ int i, dim;
- extra_stat = gnm_regression_stat_new ();
- dim = 0;
-
- if (argv[0] == NULL || (argv[0]->type != VALUE_ARRAY && argv[0]->type != VALUE_CELLRANGE)){
- goto out; /* Not a valid input for ys */
- }
-
- if (argv[0]->type == VALUE_ARRAY)
- ytype = ARRAY;
- else if (argv[0]->v_range.cell.a.col == argv[0]->v_range.cell.b.col)
- ytype = SINGLE_COL;
- else if (argv[0]->v_range.cell.a.row == argv[0]->v_range.cell.b.row)
- ytype = SINGLE_ROW;
- else ytype = OTHER;
-
- if (argv[0]->type == VALUE_CELLRANGE) {
- ys = collect_floats_value (argv[0], ei->pos,
- COLLECT_IGNORE_STRINGS |
- COLLECT_IGNORE_BOOLS,
- &ny, &result);
- } else if (argv[0]->type == VALUE_ARRAY) {
- ny = 0;
- /*
- * Get ys from array argument argv[0]
- */
- }
-
- if (result || ny < 1)
- goto out;
-
- /* TODO Better error-checking in next statement */
-
- if (argv[1] == NULL || (ytype == ARRAY && argv[1]->type != VALUE_ARRAY) ||
- (ytype != ARRAY && argv[1]->type != VALUE_CELLRANGE)){
- xarg = 0;
- dim = 1;
- xss = g_new (gnm_float *, 1);
- xss[0] = g_new (gnm_float, ny);
- for (nx = 0; nx < ny; nx++)
- xss[0][nx] = nx + 1;
- } else if (ytype == ARRAY){
- /* Get xss from array argument argv[1] */
- nx = 0;
- } else if (ytype == SINGLE_COL){
- GnmValue *copy = value_dup (argv[1]);
- int firstcol = argv[1]->v_range.cell.a.col;
- int lastcol = argv[1]->v_range.cell.b.col;
- if (firstcol > lastcol) {
- int tmp = firstcol;
- firstcol = lastcol;
- lastcol = tmp;
- }
-
- dim = lastcol - firstcol + 1;
- xss = g_new (gnm_float *, dim);
- for (i = firstcol; i <= lastcol; i++){
- copy->v_range.cell.a.col = i;
- copy->v_range.cell.b.col = i;
- xss[i - firstcol] = collect_floats_value (copy, ei->pos,
- COLLECT_IGNORE_STRINGS |
- COLLECT_IGNORE_BOOLS,
- &nx, &result);
- if (result){
- value_release (copy);
- dim = i - firstcol; /*How many got allocated before failure*/
- goto out;
- }
- if (nx != ny){
- value_release (copy);
- dim = i - firstcol + 1;
- result = value_new_error_NUM (ei->pos);
- goto out;
- }
- }
- value_release (copy);
- } else if (ytype == SINGLE_ROW) {
- GnmValue *copy = value_dup (argv[1]);
- int firstrow = argv[1]->v_range.cell.a.row;
- int lastrow = argv[1]->v_range.cell.b.row;
- if (firstrow > lastrow) {
- int tmp = firstrow;
- firstrow = lastrow;
- lastrow = tmp;
- }
-
- dim = lastrow - firstrow + 1;
- xss = g_new (gnm_float *, dim);
- for (i = firstrow; i <= lastrow; i++){
- copy->v_range.cell.a.row = i;
- copy->v_range.cell.b.row = i;
- xss[i - firstrow] = collect_floats_value (copy, ei->pos,
- COLLECT_IGNORE_STRINGS |
- COLLECT_IGNORE_BOOLS,
- &nx, &result);
- if (result){
- value_release (copy);
- dim = i - firstrow; /*How many got allocated before failure*/
- goto out;
- }
- if (nx != ny){
- value_release (copy);
- dim = i - firstrow + 1;
- result = value_new_error_NUM (ei->pos);
- goto out;
- }
- }
- value_release (copy);
- } else { /*Y is none of the above */
- dim = 1;
- xss = g_new (gnm_float *, dim);
- xss[0] = collect_floats_value (argv[1], ei->pos,
- COLLECT_IGNORE_STRINGS |
- COLLECT_IGNORE_BOOLS,
- &nx, &result);
- if (result){
- dim = 0;
- goto out;
- }
- if (nx != ny){
- dim = 1;
- result = value_new_error_NUM (ei->pos);
- goto out;
- }
- }
-
- if (argv[1 + xarg]) {
- affine = value_get_as_bool (argv[1 + xarg], &err) ? 1 : 0;
- if (err) {
- result = value_new_error_VALUE (ei->pos);
- goto out;
- }
- } else
- affine = 1;
+ result = gnm_reg_data_collect (argv[0], argv[1], &data, ei->pos);
+ if (result)
+ return result;
+ dim = data.dim;
- if (argv[2 + xarg]) {
- stat = value_get_as_bool (argv[2 + xarg], &err);
- if (err) {
- result = value_new_error_VALUE (ei->pos);
- goto out;
- }
- } else
- stat = FALSE;
+ affine = argv[2] ? value_get_as_checked_bool (argv[2]) : TRUE;
+ withstat = argv[3] ? value_get_as_checked_bool (argv[3]) : FALSE;
expres = g_new (gnm_float, dim + 1);
- regres = gnm_exponential_regression (xss, dim, ys, nx, affine,
+ extra_stat = gnm_regression_stat_new ();
+ regres = gnm_exponential_regression (data.xss, dim,
+ data.ys, data.n, affine,
expres, extra_stat);
switch (regres) {
case GO_REG_ok:
@@ -4180,13 +3865,13 @@ gnumeric_logest (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
goto out;
}
- if (stat) {
+ if (withstat) {
result = value_new_array (dim + 1, 5);
value_array_set (result, 0, 2,
value_new_float (extra_stat->sqr_r));
value_array_set (result, 1, 2,
- value_new_float (gnm_sqrt (extra_stat->var))); /* Still wrong ! */
+ value_new_float (gnm_sqrt (extra_stat->var)));
value_array_set (result, 0, 3,
value_new_float (extra_stat->F));
value_array_set (result, 1, 3,
@@ -4197,23 +3882,20 @@ gnumeric_logest (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
value_new_float (extra_stat->ss_resid));
for (i = 0; i < dim; i++)
value_array_set (result, dim - i - 1, 1,
- value_new_float (extra_stat->se[i + affine]));
+ value_new_float (extra_stat->se[i+affine]));
value_array_set (result, dim, 1,
- value_new_float (extra_stat->se[0]));
+ affine ? value_new_float (extra_stat->se[0])
+ : value_new_error_NA (ei->pos));
} else
result = value_new_array (dim + 1, 1);
value_array_set (result, dim, 0, value_new_float (expres[0]));
for (i = 0; i < dim; i++)
- value_array_set (result, dim - i - 1, 0, value_new_float (expres[i + 1]));
+ value_array_set (result, dim - i - 1, 0,
+ value_new_float (expres[i + 1]));
out:
- if (xss) {
- for (i = 0; i < dim; i++)
- g_free (xss[i]);
- g_free (xss);
- }
- g_free (ys);
+ gnm_reg_data_free (&data);
g_free (expres);
gnm_regression_stat_destroy (extra_stat);
@@ -5028,7 +4710,7 @@ gnumeric_lkstest (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
value_array_set (result, 0, 2,
value_new_int (n));
- if ((n < 5) || gnm_range_average (xs, n, &mu)
+ if ((n < 5) || gnm_range_average (xs, n, &mu)
|| gnm_range_stddev_est (xs, n, &sigma)) {
value_array_set (result, 0, 0,
value_new_error_VALUE (ei->pos));
@@ -5073,7 +4755,7 @@ gnumeric_lkstest (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
} else
nd = n;
- p = gnm_exp (-7.01256 * stat * stat * (nd + 2.78019) + 2.99587 * stat * gnm_sqrt (nd + 2.78019)
+ p = gnm_exp (-7.01256 * stat * stat * (nd + 2.78019) + 2.99587 * stat * gnm_sqrt (nd + 2.78019)
- 0.122119 + 0.974598/gnm_sqrt(nd) + 1.67997/nd);
if (p > 0.1) {
@@ -5102,7 +4784,7 @@ gnumeric_lkstest (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
value_array_set (result, 0, 0,
value_new_float (p));
}
-
+
out:
g_free (xs);
@@ -5167,26 +4849,26 @@ gnumeric_sftest (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
} else {
gnm_float p;
gnm_float u, v, mu, sig;
-
+
stat = stat * stat;
-
+
value_array_set (result, 0, 1,
value_new_float (stat));
-
+
u = gnm_log (n);
v = gnm_log (u);
mu = -1.2725 + 1.0521 * (v - u);
sig = 1.0308 - 0.26758 * (v + 2./u);
- p = pnorm (gnm_log (1. - stat), mu, sig, FALSE, FALSE);
-
+ p = pnorm (gnm_log (1. - stat), mu, sig, FALSE, FALSE);
+
value_array_set (result, 0, 0,
value_new_float (p));
}
g_free (ys);
g_free (zs);
}
-
+
out:
g_free (xs);
@@ -5229,7 +4911,7 @@ gnumeric_cvmtest (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
value_array_set (result, 0, 2,
value_new_int (n));
- if ((n < 8) || gnm_range_average (xs, n, &mu)
+ if ((n < 8) || gnm_range_average (xs, n, &mu)
|| gnm_range_stddev_est (xs, n, &sigma)) {
value_array_set (result, 0, 0,
value_new_error_VALUE (ei->pos));
@@ -5255,11 +4937,11 @@ gnumeric_cvmtest (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
value_new_float (total));
g_free (ys);
-
+
total *= (1 + 0.5 / n);
if (total < 0.0275)
p = 1. - gnm_exp (-13.953 + 775.5 * total - 12542.61 * total * total);
- else if (total < 0.051)
+ else if (total < 0.051)
p = 1. - gnm_exp (-5.903 + 179.546 * total - 1515.29 * total * total);
else if (total < 0.092)
p = gnm_exp (0.886 - 31.62 * total - 10.897 * total * total);
@@ -5271,7 +4953,7 @@ gnumeric_cvmtest (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
value_array_set (result, 0, 0,
value_new_float (p));
}
-
+
out:
g_free (xs);
@@ -5314,7 +4996,7 @@ gnumeric_adtest (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
value_array_set (result, 0, 2,
value_new_int (n));
- if ((n < 8) || gnm_range_average (xs, n, &mu)
+ if ((n < 8) || gnm_range_average (xs, n, &mu)
|| gnm_range_stddev_est (xs, n, &sigma)) {
value_array_set (result, 0, 0,
value_new_error_VALUE (ei->pos));
@@ -5338,11 +5020,11 @@ gnumeric_adtest (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
value_new_float (total));
g_free (ys);
-
+
total *= (1 + 0.75 / n + 2.25 / (n * n));
if (total < 0.2)
p = 1. - gnm_exp (-13.436 + 101.14 * total - 223.73 * total * total);
- else if (total < 0.34)
+ else if (total < 0.34)
p = 1. - gnm_exp (-8.318 + 42.796 * total - 59.938 * total * total);
else if (total < 0.6)
p = gnm_exp (0.9177 - 4.279 * total - 1.38 * total * total);
@@ -5352,7 +5034,7 @@ gnumeric_adtest (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
value_array_set (result, 0, 0,
value_new_float (p));
}
-
+
out:
g_free (xs);
@@ -5364,19 +5046,19 @@ gnumeric_adtest (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
GnmFuncDescriptor const stat_functions[] = {
{ "adtest", "A",
help_adtest, gnumeric_adtest, NULL, NULL, NULL, NULL,
- GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
+ GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
{ "sftest", "A",
help_sftest, gnumeric_sftest, NULL, NULL, NULL, NULL,
- GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
+ GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
{ "cvmtest", "A",
help_cvmtest, gnumeric_cvmtest, NULL, NULL, NULL, NULL,
- GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
+ GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
{ "lkstest", "A",
help_lkstest, gnumeric_lkstest, NULL, NULL, NULL, NULL,
- GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
+ GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
{ "avedev", NULL,
help_avedev, NULL, gnumeric_avedev, NULL, NULL, NULL,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]