gnumeric r16922 - in trunk: . plugins/fn-random
- From: mortenw svn gnome org
- To: svn-commits-list gnome org
- Subject: gnumeric r16922 - in trunk: . plugins/fn-random
- Date: Fri, 24 Oct 2008 14:28:37 +0000 (UTC)
Author: mortenw
Date: Fri Oct 24 14:28:37 2008
New Revision: 16922
URL: http://svn.gnome.org/viewvc/gnumeric?rev=16922&view=rev
Log:
2008-10-24 Morten Welinder <terra gnome org>
* functions.c (gnumeric_randdiscrete): Simplify and fix crash
#557682.
Modified:
trunk/NEWS
trunk/plugins/fn-random/ChangeLog
trunk/plugins/fn-random/functions.c
Modified: trunk/NEWS
==============================================================================
--- trunk/NEWS (original)
+++ trunk/NEWS Fri Oct 24 14:28:37 2008
@@ -16,6 +16,8 @@
* Fix undo problem with auto filters. [#557591]
* Remove the effect on an auto filter when its column is removed.
* Plug leaks.
+ * Remove the effect on an auto filter column when removed.
+ * Fix RANDDISCRETE crash. [#557682]
--------------------------------------------------------------------------
Gnumeric 1.9.3
Modified: trunk/plugins/fn-random/functions.c
==============================================================================
--- trunk/plugins/fn-random/functions.c (original)
+++ trunk/plugins/fn-random/functions.c Fri Oct 24 14:28:37 2008
@@ -129,112 +129,72 @@
{ GNM_FUNC_HELP_END }
};
-typedef struct {
- gnm_float *prob;
- int ind;
- gnm_float x;
- gnm_float cum;
- int x_ind;
- GnmValue *res;
-} randdiscrete_t;
-
-static GnmValue *
-cb_randdiscrete (GnmCellIter const *iter, gpointer user)
-{
- randdiscrete_t *p = (randdiscrete_t *) user;
- GnmCell *cell = iter->cell;
-
- if (p->res != NULL)
- return NULL;
-
- if (p->prob) {
- if (p->x <= p->prob [p->ind] + p->cum) {
- if (cell != NULL) {
- gnm_cell_eval (cell);
- p->res = value_dup (cell->value);
- } else
- p->res = value_new_empty ();
- } else
- p->cum += p->prob [p->ind];
- } else if (p->ind == p->x_ind) {
- if (cell != NULL) {
- gnm_cell_eval (cell);
- p->res = value_dup (cell->value);
- } else
- p->res = value_new_empty ();
- }
- (p->ind)++;
-
- return NULL;
-}
-
static GnmValue *
gnumeric_randdiscrete (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
- GnmValue const *value_range = argv[0];
- GnmValue const *prob_range = argv[1];
- GnmValue *ret;
- int cols, rows;
- randdiscrete_t rd;
-
- rd.prob = NULL;
- rd.ind = 0;
- rd.cum = 0;
- rd.res = NULL;
- rd.x_ind = 0;
-
- if (value_range->type != VALUE_CELLRANGE ||
- (prob_range != NULL && prob_range->type != VALUE_CELLRANGE))
- return value_new_error_VALUE (ei->pos);
-
- cols = value_range->v_range.cell.b.col
- - value_range->v_range.cell.a.col + 1;
- rows = value_range->v_range.cell.b.row
- - value_range->v_range.cell.a.row + 1;
-
- rd.x = random_01 ();
-
- if (prob_range) {
- int n;
- gnm_float sum;
-
- if (prob_range->v_range.cell.b.col
- - prob_range->v_range.cell.a.col + 1 != cols
- || prob_range->v_range.cell.b.row
- - prob_range->v_range.cell.a.row + 1 != rows)
- return value_new_error_NUM (ei->pos);
-
- rd.prob = collect_floats_value (prob_range, ei->pos, 0, &n,
- &ret);
-
- /* Check that the cumulative probability equals to one. */
- go_range_sum (rd.prob, n, &sum);
- if (sum != 1) {
- g_free (rd.prob);
- return value_new_error_NUM (ei->pos);
- }
+ GnmValue *res = NULL;
+ gnm_float *values = NULL;
+ gnm_float *probs = NULL;
+ int nv, np, i;
+ gnm_float p;
+
+ values = collect_floats_value (argv[0], ei->pos,
+ COLLECT_IGNORE_STRINGS |
+ COLLECT_IGNORE_BOOLS |
+ COLLECT_IGNORE_BLANKS,
+ &nv, &res);
+ if (res)
+ goto out;
+
+ if (argv[1]) {
+ probs = collect_floats_value (argv[1], ei->pos,
+ COLLECT_IGNORE_STRINGS |
+ COLLECT_IGNORE_BOOLS |
+ COLLECT_IGNORE_BLANKS,
+ &np, &res);
+ if (res)
+ goto out;
} else
- rd.x_ind = rd.x * cols * rows;
+ np = nv;
- ret = sheet_foreach_cell_in_range
- (eval_sheet (value_range->v_range.cell.a.sheet, ei->pos->sheet),
- CELL_ITER_ALL,
- value_range->v_range.cell.a.col,
- value_range->v_range.cell.a.row,
- value_range->v_range.cell.b.col,
- value_range->v_range.cell.b.row,
- cb_randdiscrete,
- &rd);
-
- g_free (rd.prob);
-
- if (ret != NULL) {
- g_free (rd.res);
- return value_new_error_VALUE (ei->pos);
+ if (nv < 1 || nv != np)
+ goto error;
+
+ if (probs) {
+ gnm_float pmin, psum;
+
+ gnm_range_min (probs, np, &pmin);
+ if (pmin < 0)
+ goto error;
+
+ gnm_range_sum (probs, np, &psum);
+ if (gnm_abs (psum - 1) > 1e-10)
+ goto error;
+ }
+
+ p = random_01 ();
+ if (probs) {
+ for (i = 0; i < np; i++) {
+ p -= probs[i];
+ if (p < 0)
+ break;
+ }
+ } else {
+ /* Uniform. */
+ i = (int)gnm_floor (p * nv);
}
- return rd.res;
+ /* MIN is needed because of the sum grace. */
+ res = value_new_float (values[MIN (i, nv - 1)]);
+ out:
+ g_free (values);
+ g_free (probs);
+ return res;
+
+ error:
+ res = value_new_error_NUM (ei->pos);
+ goto out;
}
/***************************************************************************/
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]