[gnumeric] BINOM.DIST.RANGE: improve accuracy.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnumeric] BINOM.DIST.RANGE: improve accuracy.
- Date: Mon, 14 Jun 2010 15:50:27 +0000 (UTC)
commit b298883667ef65c167f188163866bb543f741380
Author: Morten Welinder <terra gnome org>
Date: Mon Jun 14 11:50:05 2010 -0400
BINOM.DIST.RANGE: improve accuracy.
ChangeLog | 5 ++
NEWS | 1 +
plugins/fn-stat/ChangeLog | 2 +
plugins/fn-stat/functions.c | 105 +++++++++++++++++++-----------------------
src/mathfunc.c | 26 +++++++++++
src/mathfunc.h | 1 +
6 files changed, 83 insertions(+), 57 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 9bd533d..c1e0d5f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2010-06-14 Morten Welinder <terra gnome org>
+
+ * src/mathfunc.c (pbinom2): New function extracted from
+ gnumeric_binom_dist_range and improved.
+
2010-06-13 Morten Welinder <terra gnome org>
* src/func.c (check_help_expression): New function.
diff --git a/NEWS b/NEWS
index 2409b33..403bb5c 100644
--- a/NEWS
+++ b/NEWS
@@ -39,6 +39,7 @@ Morten:
* Improve help text sanity checks.
* Fix minor parsing problem.
* Handle missing data in FORECAST properly. [#621417]
+ * Improve BINOM.DIST.RANGE.
--------------------------------------------------------------------------
Gnumeric 1.10.5
diff --git a/plugins/fn-stat/ChangeLog b/plugins/fn-stat/ChangeLog
index 023f8ca..0bfb021 100644
--- a/plugins/fn-stat/ChangeLog
+++ b/plugins/fn-stat/ChangeLog
@@ -2,6 +2,8 @@
* functions.c (gnumeric_forecast): Handle missing data properly.
Fixes #621417.
+ (gnumeric_binom_dist_range): Fix precision problem when both
+ end-points are near the number of trial.
2010-06-13 Morten Welinder <terra gnome org>
diff --git a/plugins/fn-stat/functions.c b/plugins/fn-stat/functions.c
index ac65c84..d6b019b 100644
--- a/plugins/fn-stat/functions.c
+++ b/plugins/fn-stat/functions.c
@@ -180,7 +180,8 @@ gnumeric_rank (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
gnm_float *xs;
int i, r, n;
GnmValue *result = NULL;
- gnm_float x, order;
+ gnm_float x;
+ gboolean increasing;
x = value_get_as_float (argv[0]);
xs = collect_floats_value (argv[1], ei->pos,
@@ -189,7 +190,7 @@ gnumeric_rank (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
COLLECT_IGNORE_BLANKS |
COLLECT_ORDER_IRRELEVANT,
&n, &result);
- order = argv[2] ? value_get_as_int (argv[2]) : 0;
+ increasing = argv[2] ? value_get_as_checked_bool (argv[2]) : FALSE;
if (result)
goto out;
@@ -197,7 +198,7 @@ gnumeric_rank (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
for (i = 0, r = 1; i < n; i++) {
gnm_float y = xs[i];
- if (order ? y < x : y > x)
+ if (increasing ? y < x : y > x)
r++;
}
@@ -231,7 +232,8 @@ gnumeric_rank_avg (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
gnm_float *xs;
int i, r, n, t;
GnmValue *result = NULL;
- gnm_float x, order;
+ gnm_float x;
+ gboolean increasing;
x = value_get_as_float (argv[0]);
xs = collect_floats_value (argv[1], ei->pos,
@@ -240,7 +242,7 @@ gnumeric_rank_avg (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
COLLECT_IGNORE_BLANKS |
COLLECT_ORDER_IRRELEVANT,
&n, &result);
- order = argv[2] ? value_get_as_int (argv[2]) : 0;
+ increasing = argv[2] ? value_get_as_checked_bool (argv[2]) : FALSE;
if (result)
goto out;
@@ -248,7 +250,7 @@ gnumeric_rank_avg (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
for (i = 0, r = 1, t = 0; i < n; i++) {
gnm_float y = xs[i];
- if (order ? y < x : y > x)
+ if (increasing ? y < x : y > x)
r++;
if (x == y)
t++;
@@ -394,8 +396,8 @@ static GnmFuncHelp const help_negbinomdist[] = {
static GnmValue *
gnumeric_negbinomdist (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
- int x = value_get_as_int (argv[0]);
- int r = value_get_as_int (argv[1]);
+ gnm_float x = gnm_fake_floor (value_get_as_float (argv[0]));
+ gnm_float r = gnm_fake_floor (value_get_as_float (argv[1]));
gnm_float p = value_get_as_float (argv[2]);
if ((x + r - 1) <= 0 || p < 0 || p > 1)
@@ -884,7 +886,7 @@ static GnmFuncHelp const help_bernoulli[] = {
};
static gnm_float
-random_bernoulli_pdf (int k, gnm_float p)
+random_bernoulli_pdf (gnm_float k, gnm_float p)
{
if (k == 0)
return 1 - p;
@@ -897,7 +899,7 @@ random_bernoulli_pdf (int k, gnm_float p)
static GnmValue *
gnumeric_bernoulli (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
- gnm_float k = value_get_as_int (argv[0]);
+ gnm_float k = value_get_as_float (argv[0]);
gnm_float p = value_get_as_float (argv[1]);
if (p < 0 || p > 1 || (k != 0 && k != 1))
@@ -989,7 +991,7 @@ static GnmValue *
gnumeric_chidist (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
gnm_float x = value_get_as_float (argv[0]);
- int dof = value_get_as_int (argv[1]);
+ gnm_float dof = gnm_fake_floor (value_get_as_float (argv[1]));
if (dof < 1)
return value_new_error_NUM (ei->pos);
@@ -1016,7 +1018,7 @@ static GnmValue *
gnumeric_chiinv (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
gnm_float p = value_get_as_float (argv[0]);
- int dof = value_get_as_int (argv[1]);
+ gnm_float dof = gnm_fake_floor (value_get_as_float (argv[1]));
if (p < 0 || p > 1 || dof < 1)
return value_new_error_NUM (ei->pos);
@@ -1209,7 +1211,7 @@ gnumeric_tdist (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
gnm_float x = value_get_as_float (argv[0]);
gnm_float dof = value_get_as_float (argv[1]);
- int tails = value_get_as_int (argv[2]);
+ gnm_float tails = value_get_as_float (argv[2]);
gnm_float p;
if (dof < 1)
@@ -1291,8 +1293,8 @@ static GnmValue *
gnumeric_fdist (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
gnm_float x = value_get_as_float (argv[0]);
- int dof1 = value_get_as_int (argv[1]);
- int dof2 = value_get_as_int (argv[2]);
+ gnm_float dof1 = gnm_fake_floor (value_get_as_float (argv[1]));
+ gnm_float dof2 = gnm_fake_floor (value_get_as_float (argv[2]));
if (x < 0 || dof1 < 1 || dof2 < 1)
return value_new_error_NUM (ei->pos);
@@ -1457,8 +1459,8 @@ static GnmValue *
gnumeric_finv (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
gnm_float p = value_get_as_float (argv[0]);
- int dof1 = value_get_as_int (argv[1]);
- int dof2 = value_get_as_int (argv[2]);
+ gnm_float dof1 = gnm_fake_floor (value_get_as_float (argv[1]));
+ gnm_float dof2 = gnm_fake_floor (value_get_as_float (argv[2]));
if (p < 0 || p > 1 || dof1 < 1 || dof2 < 1)
return value_new_error_NUM (ei->pos);
@@ -1487,8 +1489,8 @@ static GnmFuncHelp const help_binomdist[] = {
static GnmValue *
gnumeric_binomdist (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
- int n = value_get_as_int (argv[0]);
- int trials = value_get_as_int (argv[1]);
+ gnm_float n = gnm_fake_floor (value_get_as_float (argv[0]));
+ gnm_float trials = gnm_fake_floor (value_get_as_float (argv[1]));
gnm_float p = value_get_as_float (argv[2]);
gboolean cuml = value_get_as_checked_bool (argv[3]);
@@ -1522,29 +1524,15 @@ static GnmFuncHelp const help_binom_dist_range[] = {
static GnmValue *
gnumeric_binom_dist_range (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
- int trials = value_get_as_int (argv[0]);
+ gnm_float trials = gnm_fake_floor (value_get_as_float (argv[0]));
gnm_float p = value_get_as_float (argv[1]);
- int start = value_get_as_int (argv[2]);
- int end = argv[3] ? value_get_as_int (argv[3]) : start;
+ gnm_float start = gnm_fake_floor (value_get_as_float (argv[2]));
+ gnm_float end = argv[3] ? gnm_fake_floor (value_get_as_float (argv[3])) : start;
if (trials < 0 || p < 0 || p > 1)
return value_new_error_NUM (ei->pos);
- if (start > trials || end < 0 || start > end)
- return value_new_float (0.);
-
- if (start == 0 && end == trials)
- return value_new_float (1.);
-
- if (start != end) {
- if (start == 0)
- return value_new_float (pbinom (end, trials, p, TRUE, FALSE));
- else if (end == trials)
- return value_new_float (pbinom (start, trials, p, FALSE, FALSE));
- else
- return value_new_float (pbinom (end, trials, p, TRUE, FALSE) - pbinom (start - 1, trials, p, TRUE, FALSE));
- } else
- return value_new_float (dbinom (start, trials, p, FALSE));
+ return value_new_float (pbinom2 (start, end, trials, p));
}
/***************************************************************************/
@@ -1597,7 +1585,7 @@ static GnmFuncHelp const help_critbinom[] = {
static GnmValue *
gnumeric_critbinom (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
- int trials = value_get_as_int (argv[0]);
+ gnm_float trials = gnm_fake_floor (value_get_as_float (argv[0]));
gnm_float p = value_get_as_float (argv[1]);
gnm_float alpha = value_get_as_float (argv[2]);
@@ -1624,8 +1612,8 @@ static GnmFuncHelp const help_permut[] = {
static GnmValue *
gnumeric_permut (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
- int n = value_get_as_int (argv[0]);
- int k = value_get_as_int (argv[1]);
+ gnm_float n = gnm_fake_floor (value_get_as_float (argv[0]));
+ gnm_float k = gnm_fake_floor (value_get_as_float (argv[1]));
if (0 <= k && k <= n)
return value_new_float (permut (n, k));
@@ -1654,10 +1642,10 @@ static GnmFuncHelp const help_hypgeomdist[] = {
static GnmValue *
gnumeric_hypgeomdist (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
- int x = value_get_as_int (argv[0]);
- int n = value_get_as_int (argv[1]);
- int M = value_get_as_int (argv[2]);
- int N = value_get_as_int (argv[3]);
+ gnm_float x = gnm_fake_floor (value_get_as_float (argv[0]));
+ gnm_float n = gnm_fake_floor (value_get_as_float (argv[1]));
+ gnm_float M = gnm_fake_floor (value_get_as_float (argv[2]));
+ gnm_float N = gnm_fake_floor (value_get_as_float (argv[3]));
gboolean cum = argv[4] ? value_get_as_checked_bool (argv[4]) : FALSE;
if (x < 0 || n < 0 || M < 0 || N < 0 || x > M || n > N)
@@ -1689,9 +1677,9 @@ static GnmFuncHelp const help_confidence[] = {
static GnmValue *
gnumeric_confidence (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
- gnm_float x = value_get_as_float (argv[0]);
+ gnm_float x = value_get_as_float (argv[0]);
gnm_float stddev = value_get_as_float (argv[1]);
- int size = value_get_as_int (argv[2]);
+ gnm_float size = gnm_fake_floor (value_get_as_float (argv[2]));
if (size <= 0 || stddev <= 0)
return value_new_error_NUM (ei->pos);
@@ -1977,7 +1965,7 @@ static GnmFuncHelp const help_poisson[] = {
static GnmValue *
gnumeric_poisson (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
- gnm_float x = value_get_as_int (argv[0]);
+ gnm_float x = gnm_fake_floor (value_get_as_float (argv[0]));
gnm_float mean = value_get_as_float (argv[1]);
gboolean cuml = value_get_as_checked_bool (argv[2]);
@@ -3150,23 +3138,26 @@ out:
static GnmValue *
gnumeric_ttest (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
{
- int tails, type;
-
- tails = value_get_as_int (argv[2]);
- type = value_get_as_int (argv[3]);
+ gnm_float tails = value_get_as_float (argv[2]);
+ gnm_float type = value_get_as_float (argv[3]);
+ int itails;
if (tails != 1 && tails != 2)
return value_new_error_NUM (ei->pos);
+ itails = (int)tails;
+
+ if (type != 1 && type != 2 && type != 3)
+ return value_new_error_NUM (ei->pos);
- switch (type) {
+ switch ((int)type) {
case 1:
- return ttest_paired (ei, argv[0], argv[1], tails);
+ return ttest_paired (ei, argv[0], argv[1], itails);
case 2:
- return ttest_equal_unequal (ei, argv[0], argv[1], tails, FALSE);
+ return ttest_equal_unequal (ei, argv[0], argv[1], itails, FALSE);
case 3:
- return ttest_equal_unequal (ei, argv[0], argv[1], tails, TRUE);
+ return ttest_equal_unequal (ei, argv[0], argv[1], itails, TRUE);
default:
return value_new_error_NUM (ei->pos);
@@ -5224,10 +5215,10 @@ GnmFuncDescriptor const stat_functions[] = {
{ "quartile", "Af",
help_quartile, gnumeric_quartile, NULL, NULL, NULL, NULL,
GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
- { "rank", "fr|f",
+ { "rank", "fr|b",
help_rank, gnumeric_rank, NULL, NULL, NULL, NULL,
GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
- { "rank.avg", "fr|f",
+ { "rank.avg", "fr|b",
help_rank_avg, gnumeric_rank_avg, NULL, NULL, NULL, NULL,
GNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
{ "slope", "AA",
diff --git a/src/mathfunc.c b/src/mathfunc.c
index f4acfb5..dcb9a59 100644
--- a/src/mathfunc.c
+++ b/src/mathfunc.c
@@ -6314,6 +6314,32 @@ qhyper (gnm_float p, gnm_float NR, gnm_float NB, gnm_float n,
phyper1);
}
+gnm_float
+pbinom2 (gnm_float x0, gnm_float x1, gnm_float n, gnm_float p)
+{
+ gnm_float Pl;
+
+ if (x0 > n || x1 < 0 || x0 > x1)
+ return 0;
+
+ if (x0 == x1)
+ return dbinom (x0, n, p, FALSE);
+
+ if (x1 >= n)
+ return pbinom (x0, n, p, FALSE, FALSE);
+
+ Pl = pbinom (x0 - 1, n, p, TRUE, FALSE);
+ if (Pl > 0.75) {
+ gnm_float PlC = pbinom (x0 - 1, n, p, FALSE, FALSE);
+ gnm_float PrC = pbinom (x1, n, p, FALSE, FALSE);
+ return PlC - PrC;
+ } else {
+ gnm_float Pr = pbinom (x1, n, p, TRUE, FALSE);
+ return Pr - Pl;
+ }
+}
+
+
/* ------------------------------------------------------------------------- */
/* http://www.math.keio.ac.jp/matumoto/CODES/MT2002/mt19937ar.c */
/* Imported by hand -- MW. */
diff --git a/src/mathfunc.h b/src/mathfunc.h
index 3d335f2..e73837e 100644
--- a/src/mathfunc.h
+++ b/src/mathfunc.h
@@ -102,6 +102,7 @@ gnm_float qexp (gnm_float p, gnm_float scale, gboolean lower_tail, gboolean log_
/* Binomial distribution. */
gnm_float dbinom (gnm_float x, gnm_float n, gnm_float p, gboolean give_log);
gnm_float pbinom (gnm_float x, gnm_float n, gnm_float p, gboolean lower_tail, gboolean log_p);
+gnm_float pbinom2 (gnm_float x0, gnm_float x1, gnm_float n, gnm_float p);
gnm_float qbinom (gnm_float x, gnm_float n, gnm_float p, gboolean lower_tail, gboolean log_p);
/* Negative binomial distribution. */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]