[gnumeric] ptukey: improve the probablity integral.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnumeric] ptukey: improve the probablity integral.
- Date: Sun, 26 May 2013 23:17:00 +0000 (UTC)
commit 77cc964d4097c0cb21a4b8b0fbde185d05652021
Author: Morten Welinder <terra gnome org>
Date: Sun May 26 19:16:30 2013 -0400
ptukey: improve the probablity integral.
ChangeLog | 5 +++
src/mathfunc.c | 80 +++++++++++++++++++++++++++++--------------------------
2 files changed, 47 insertions(+), 38 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 5739e06..51f032a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2013-05-26 Morten Welinder <terra gnome org>
+
+ * src/mathfunc.c (ptukey_wprob): Use as many intervals as needed.
+ Termiate when contributions vanish.
+
2013-05-24 Morten Welinder <terra gnome org>
* src/mathfunc.c (R_ptukey): Accelerate handling of right tail of
diff --git a/src/mathfunc.c b/src/mathfunc.c
index 4024e30..78bd027 100644
--- a/src/mathfunc.c
+++ b/src/mathfunc.c
@@ -5170,7 +5170,6 @@ static gnm_float ptukey_wprob(gnm_float w, gnm_float rr, gnm_float cc)
wlar = value of range above which wincr1 intervals are used to
calculate second part of integral,
else wincr2 intervals are used.
- C1, C2, C3 = values which are used as cutoffs for terminating
or modifying a calculation.
M_1_SQRT_2PI = 1 / sqrt(2 * pi); from abramowitz & stegun, p. 3.
@@ -5179,13 +5178,8 @@ static gnm_float ptukey_wprob(gnm_float w, gnm_float rr, gnm_float cc)
aleg = legendre 12-point coefficients
*/
- /* looks like this is suboptimal for gnm_float precision.
- (see how C1-C3 are used) <MM>
- */
+ static const gboolean debug = FALSE;
const static gnm_float bb = 8.;
- const static gnm_float wlar = 3.;
- const static gnm_float wincr1 = 2.;
- const static gnm_float wincr2 = 3.;
const static gnm_float xleg[] = {
GNM_const(0.981560634246719250690549090149),
GNM_const(0.904117256370474856678465866119),
@@ -5203,9 +5197,8 @@ static gnm_float ptukey_wprob(gnm_float w, gnm_float rr, gnm_float cc)
GNM_const(0.249147045813402785000562436043)
};
const int nleg = G_N_ELEMENTS (xleg) * 2;
- gnm_float pr_w, binc, qsqz, wi, wincr;
- /*LDOUBLE*/ gnm_float blb, einsum;
- int jj;
+ gnm_float pr_w, binc, qsqz, blb;
+ int i, jj;
qsqz = w * 0.5;
@@ -5220,66 +5213,72 @@ static gnm_float ptukey_wprob(gnm_float w, gnm_float rr, gnm_float cc)
pr_w = gnm_pow (gnm_erf (qsqz / M_SQRT2gnum), cc);
- /* if w is large then the second component of the */
- /* integral is small, so fewer intervals are needed. */
-
- if (w > wlar)
- wincr = wincr1;
- else
- wincr = wincr2;
-
/* find the integral of second term of hartley's form */
- /* for the integral of the range for equal-length */
- /* intervals using legendre quadrature. limits of */
- /* integration are from (w/2, 8). two or three */
- /* equal-length intervals are used. */
+ /* Limits of integration are (w/2, Inf). Large cc means that */
+ /* that we need smaller step size. The formula for binc is */
+ /* a heuristic. */
/* blb and bub are lower and upper limits of integration. */
blb = qsqz;
- binc = (bb - qsqz) / wincr;
- einsum = 0.0;
+ binc = 3.0 / gnm_log1p (cc);
/* integrate over each interval */
- for (wi = 1; wi <= wincr; wi++) {
- gnm_float a = blb + binc * 0.5;
+ for (i = 1; TRUE; i++) {
+ gnm_float C = blb + binc * 0.5;
gnm_float elsum = 0.0;
/* legendre quadrature with order = nleg */
for (jj = 0; jj < nleg; jj++) {
- gnm_float xx, aa, c, ac, rinsum;
+ gnm_float xx, aa, v, rinsum;
if (nleg / 2 <= jj) {
- int j = (nleg - 1) - jj;
- xx = xleg[j];
- aa = aleg[j];
+ xx = xleg[nleg - 1 - jj];
+ aa = aleg[nleg - 1 - jj];
} else {
xx = -xleg[jj];
aa = aleg[jj];
}
- c = binc * 0.5 * xx;
- ac = a + c;
+ v = C + binc * 0.5 * xx;
- rinsum = pnorm2 (ac - w, ac, FALSE);
+ rinsum = pnorm2 (v - w, v, FALSE);
elsum += gnm_pow (rinsum, cc - 1) *
aa *
- gnm_exp(-0.5 * ac * ac);
+ gnm_exp(-0.5 * v * v);
+ }
+ elsum *= (binc * cc * M_1_SQRT_2PI);
+ pr_w += elsum;
+
+ if (pr_w >= 1) {
+ /* Nothing more will contribute. */
+ pr_w = 1;
+ break;
}
- einsum += elsum * (binc * cc * M_1_SQRT_2PI);
+
+ if (elsum <= pr_w * (GNM_EPSILON / 2)) {
+ /* This interval contributed nothing. We're done. */
+ if (debug) {
+ g_printerr ("End at i=%d for w=%g cc=%g dP=%g P=%g\n",
+ i, w, cc, elsum, pr_w);
+ }
+ break;
+ }
+
blb += binc;
}
- pr_w += einsum;
+ if (0) g_printerr ("w=%g pr_w=%.20g\n", w, pr_w);
- return gnm_pow (MIN (1.0, pr_w), rr);
+ return gnm_pow (pr_w, rr);
}
static gnm_float
ptukey_otsum (gnm_float u0, gnm_float u1, gnm_float f2, gnm_float f2lf,
gnm_float q, gnm_float rr, gnm_float cc)
{
+ gboolean debug = FALSE;
const static gnm_float xlegq[] = {
GNM_const(0.989400934991649932596154173450),
GNM_const(0.944575023073232576077988415535),
@@ -5325,6 +5324,11 @@ ptukey_otsum (gnm_float u0, gnm_float u1, gnm_float f2, gnm_float f2lf,
otsum += aa * (wprb * (0.5 * L) * gnm_exp(t1));
}
+ if (debug)
+ g_printerr ("Integral over [%g;%g] was %g\n",
+ u0, u1, otsum);
+
+
return otsum;
}
@@ -5508,7 +5512,7 @@ R_ptukey(gnm_float q, gnm_float rr, gnm_float cc, gnm_float df,
}
}
- if (i == 100) {
+ if (i == 150) {
if (debug)
g_printerr ("PTUKEY FAIL RIGHT: %i %g %g\n",
i, otsum, ans);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]