1 #include <gnumeric-config.h>
6 #define R_D__0 (log_p ? gnm_ninf : 0.0)
7 #define R_D__1 (log_p ? 0.0 : 1.0)
8 #define R_DT_0 (lower_tail ? R_D__0 : R_D__1)
9 #define R_DT_1 (lower_tail ? R_D__1 : R_D__0)
10 #define M_1_SQRT_2PI GNM_const(0.398942280401432677939946059934) /* 1/sqrt(2pi) */
11 #define M_SQRT_2PI GNM_const(2.506628274631000502415765284811045253006986740609938316629923)
13 /* ------------------------------------------------------------------------- */
15 #undef DEBUG_pfuncinverter
26 * @pfunc: (scope call):
27 * @dpfunc_dx: (scope call):
32 pfuncinverter (gnm_float p
, const gnm_float shape
[],
33 gboolean lower_tail
, gboolean log_p
,
34 gnm_float xlow
, gnm_float xhigh
, gnm_float x0
,
35 GnmPFunc pfunc
, GnmDPFunc dpfunc_dx
)
37 gboolean have_xlow
= gnm_finite (xlow
);
38 gboolean have_xhigh
= gnm_finite (xhigh
);
39 gnm_float exlow
, exhigh
;
40 gnm_float x
= 0, e
= 0, px
;
43 g_return_val_if_fail (pfunc
!= NULL
, gnm_nan
);
45 if (log_p
? (p
> 0) : (p
< 0 || p
> 1))
48 if (p
== R_DT_0
) return xlow
;
49 if (p
== R_DT_1
) return xhigh
;
58 #ifdef DEBUG_pfuncinverter
59 g_printerr ("p=%.15g\n", p
);
62 for (i
= 0; i
< 100; i
++) {
64 if (x0
> xlow
&& x0
< xhigh
)
65 /* Use supplied guess. */
67 else if (have_xlow
&& x0
<= xlow
)
68 x
= xlow
+ have_xhigh
? (xhigh
- xlow
) / 100 : 1;
69 else if (have_xhigh
&& x0
>= xhigh
)
70 x
= xhigh
- have_xlow
? (xhigh
- xlow
) / 100 : 1;
75 * Under the assumption that the initial guess was
76 * good, pick a nearby point that is hopefully on
77 * the other side. If we already have both sides,
80 if (have_xlow
&& have_xhigh
)
81 x
= (xlow
+ xhigh
) / 2;
86 } else if (have_xlow
&& have_xhigh
) {
89 x
= xhigh
- (xhigh
- xlow
) *
90 (exhigh
/ (exhigh
- exlow
));
93 /* Half-way in log-space. */
94 if (xlow
>= 0 && xhigh
>= 0)
95 x
= gnm_sqrt (MAX (GNM_MIN
, xlow
)) * gnm_sqrt (xhigh
);
96 else if (xlow
<= 0 && xhigh
<= 0)
97 x
= -gnm_sqrt (-xlow
) * gnm_sqrt (MAX (GNM_MIN
, -xhigh
));
102 x
= (xhigh
+ 1000 * xlow
) / 1001;
105 x
= (1000 * xhigh
+ xlow
) / 1001;
108 x
= (xhigh
+ xlow
) / 2;
110 } else if (have_xlow
) {
111 /* Agressively seek right in search of xhigh. */
112 x
= (xlow
< 1) ? 1 : (2 * i
) * xlow
;
114 /* Agressively seek left in search of xlow. */
115 x
= (xhigh
> -1) ? -1 : (2 * i
) * xhigh
;
119 if ((have_xlow
&& x
<= xlow
) || (have_xhigh
&& x
>= xhigh
))
122 px
= pfunc (x
, shape
, lower_tail
, log_p
);
124 if (!lower_tail
) e
= -e
;
126 #ifdef DEBUG_pfuncinverter
127 g_printerr ("%3d: x=%.15g e=%.15g l=%.15g h=%.15g\n",
128 i
, x
, e
, xlow
, xhigh
);
145 if (have_xlow
&& have_xhigh
) {
146 gnm_float prec
= (xhigh
- xlow
) /
147 (gnm_abs (xlow
) + gnm_abs (xhigh
));
148 if (prec
< GNM_EPSILON
* 4) {
149 x
= (xhigh
+ xlow
) / 2;
150 e
= pfunc (x
, shape
, lower_tail
, log_p
) - p
;
151 if (!lower_tail
) e
= -e
;
155 if (dpfunc_dx
&& i
% 3 < 2 && (i
== 0 || prec
< 0.05)) {
156 gnm_float d
= dpfunc_dx (x
, shape
, log_p
);
157 if (log_p
) d
= gnm_exp (d
- px
);
158 #ifdef DEBUG_pfuncinverter
159 g_printerr ("Newton: d=%-.14g\n", d
);
163 * Deliberately overshoot a bit to help
164 * with getting good points on both
167 x
= x
- e
/ d
* 1.000001;
168 if (x
> xlow
&& x
< xhigh
) {
169 #ifdef DEBUG_pfuncinverter
170 g_printerr ("Newton ok\n");
176 #ifdef DEBUG_pfuncinverter
177 g_printerr ("Newton d=0\n");
184 #ifdef DEBUG_pfuncinverter
185 g_printerr ("Failed to converge\n");
189 /* Make sure to keep a lucky near-hit. */
191 if (have_xhigh
&& gnm_abs (e
) > exhigh
)
192 e
= exhigh
, x
= xhigh
;
193 if (have_xlow
&& gnm_abs (e
) > -exlow
)
196 #ifdef DEBUG_pfuncinverter
197 g_printerr ("--> %.15g\n\n", x
);
211 * @pfunc: (scope call):
213 * Discrete pfuncs only. (Specifically: only integer x are allowed).
217 discpfuncinverter (gnm_float p
, const gnm_float shape
[],
218 gboolean lower_tail
, gboolean log_p
,
219 gnm_float xlow
, gnm_float xhigh
, gnm_float x0
,
222 gboolean have_xlow
= gnm_finite (xlow
);
223 gboolean have_xhigh
= gnm_finite (xhigh
);
224 gboolean check_left
= TRUE
;
228 if (log_p
? (p
> 0) : (p
< 0 || p
> 1))
231 if (p
== R_DT_0
) return xlow
;
232 if (p
== R_DT_1
) return xhigh
;
234 if (gnm_finite (x0
) && x0
>= xlow
&& x0
<= xhigh
)
235 ; /* Nothing -- guess is good. */
236 else if (have_xlow
&& have_xhigh
)
237 x0
= (xlow
+ xhigh
) / 2;
244 x0
= gnm_floor (x0
+ 0.5);
245 step
= 1 + gnm_floor (gnm_abs (x0
) * GNM_EPSILON
);
248 g_printerr ("step=%.20g\n", step
);
251 for (i
= 1; 1; i
++) {
252 gnm_float ex0
= pfunc (x0
, shape
, lower_tail
, log_p
) - p
;
254 g_printerr ("x=%.20g e=%.20g\n", x0
, ex0
);
256 if (!lower_tail
) ex0
= -ex0
;
261 xlow
= x0
, have_xlow
= TRUE
, check_left
= FALSE
;
263 xhigh
= x0
, have_xhigh
= TRUE
, step
= -gnm_abs (step
);
265 if (i
> 1 && have_xlow
&& have_xhigh
) {
266 gnm_float xmid
= gnm_floor ((xlow
+ xhigh
) / 2);
267 if (xmid
- xlow
< 0.5 ||
268 xmid
- xlow
< gnm_abs (xlow
) * GNM_EPSILON
) {
271 * The lower edge of the support might
272 * have a probability higher than what
273 * we are looking for.
275 gnm_float e
= pfunc (xlow
, shape
, lower_tail
, log_p
) - p
;
276 if (!lower_tail
) e
= -e
;
284 gnm_float x1
= x0
+ step
;
287 /* Probably infinite. */
289 } else if (x1
>= xlow
&& x1
<= xhigh
) {
293 /* We went off the edge by walking too fast. */
294 gnm_float newstep
= 1 + gnm_floor (gnm_abs (x0
) * GNM_EPSILON
);
295 step
= (step
> 0) ? newstep
: -newstep
;
297 if (x1
>= xlow
&& x1
<= xhigh
)
300 * We don't seem to find a finite x on the
301 * other side of the root.
303 return (step
> 0) ? xhigh
: xlow
;
308 g_assert_not_reached ();
311 /* ------------------------------------------------------------------------ */
316 * @mu: mean of the distribution
317 * @sigma: standard deviation of the distribution
318 * @give_log: if %TRUE, log of the result will be returned instead
320 * Returns: density of the normal distribution.
323 dnorm (gnm_float x
, gnm_float mu
, gnm_float sigma
, gboolean give_log
)
327 if (gnm_isnan (x
) || gnm_isnan (mu
) || gnm_isnan (sigma
))
328 return x
+ mu
+ sigma
;
333 x
= x0
= gnm_abs (x
- mu
);
337 return -(M_LN_SQRT_2PI
+ 0.5 * x
* x
+ gnm_log (sigma
));
338 else if (x
> 3 + 2 * gnm_sqrt (gnm_log (GNM_MAX
)))
339 /* Far into the tail; x > ~100 for long double */
343 * Split x into xh+xl such that:
345 * 2) 0 <= xl <= 1/65536
346 * 3) 0 <= xl*xh < ~100/65536
348 gnm_float xh
= gnm_floor (x
* 65536) / 65536; /* At most 24 bits */
349 gnm_float xl
= (x0
- xh
* sigma
) / sigma
;
350 return M_1_SQRT_2PI
*
351 gnm_exp (-0.5 * (xh
* xh
)) *
352 gnm_exp (-xl
* (0.5 * xl
+ xh
)) /
355 /* Near-center case. */
356 return M_1_SQRT_2PI
* expmx2h (x
) / sigma
;
360 pnorm2 (gnm_float x1
, gnm_float x2
)
362 if (gnm_isnan (x1
) || gnm_isnan (x2
))
366 return 0 - pnorm2 (x2
, x1
);
368 /* A bunch of special cases: */
372 return pnorm (x2
, 0.0, 1.0, TRUE
, FALSE
);
374 return pnorm (x1
, 0.0, 1.0, FALSE
, FALSE
);
376 return gnm_erf (x2
/ M_SQRT2gnum
) / 2;
378 return gnm_erf (x1
/ -M_SQRT2gnum
) / 2;
380 if (x1
<= 0 && x2
>= 0) {
381 /* The interval spans 0. */
382 gnm_float p1
= pnorm2 (0, MIN (-x1
, x2
));
383 gnm_float p2
= pnorm2 (MIN (-x1
, x2
), MAX (-x1
, x2
));
386 /* Both < 0 -- use symmetry */
387 return pnorm2 (-x2
, -x1
);
390 gnm_float p1C
= pnorm (x1
, 0.0, 1.0, FALSE
, FALSE
);
391 gnm_float p2C
= pnorm (x2
, 0.0, 1.0, FALSE
, FALSE
);
392 gnm_float raw
= p1C
- p2C
;
393 gnm_float dx
, d1
, d2
, ub
, lb
;
395 if (gnm_abs (p1C
- p2C
) * 32 > gnm_abs (p1C
+ p2C
))
398 /* dnorm is strictly decreasing in this area. */
400 d1
= dnorm (x1
, 0.0, 1.0, FALSE
);
401 d2
= dnorm (x2
, 0.0, 1.0, FALSE
);
402 ub
= dx
* d1
; /* upper bound */
403 lb
= dx
* d2
; /* lower bound */
411 /* ------------------------------------------------------------------------ */
416 * @logmean: mean of the underlying normal distribution
417 * @logsd: standard deviation of the underlying normal distribution
418 * @give_log: if %TRUE, log of the result will be returned instead
420 * Returns: density of the log-normal distribution.
423 dlnorm (gnm_float x
, gnm_float logmean
, gnm_float logsd
, gboolean give_log
)
426 GnmQuad qx
, qlx
, qs
, qy
, qt
;
427 static GnmQuad qsqrt2pi
;
430 if (gnm_isnan (x
) || gnm_isnan (logmean
) || gnm_isnan (logsd
))
431 return x
+ logmean
+ logsd
;
439 state
= gnm_quad_start ();
441 gnm_quad_sqrt (&qsqrt2pi
, &gnm_quad_2pi
);
442 gnm_quad_init (&qx
, x
);
443 gnm_quad_log (&qlx
, &qx
);
444 gnm_quad_init (&qt
, logmean
);
445 gnm_quad_sub (&qy
, &qlx
, &qt
);
446 gnm_quad_init (&qs
, logsd
);
447 gnm_quad_div (&qy
, &qy
, &qs
);
448 gnm_quad_mul (&qy
, &qy
, &qy
);
449 qy
.h
*= -0.5; qy
.l
*= -0.5;
450 gnm_quad_mul (&qt
, &qs
, &qx
);
451 gnm_quad_mul (&qt
, &qt
, &qsqrt2pi
);
453 gnm_quad_log (&qt
, &qt
);
454 gnm_quad_sub (&qy
, &qy
, &qt
);
456 gnm_quad_exp (&qy
, NULL
, &qy
);
457 gnm_quad_div (&qy
, &qy
, &qt
);
459 r
= gnm_quad_value (&qy
);
460 gnm_quad_end (state
);
465 /* ------------------------------------------------------------------------ */
470 * @logmean: mean of the underlying normal distribution
471 * @logsd: standard deviation of the underlying normal distribution
472 * @lower_tail: if %TRUE, the lower tail of the distribution is considered.
473 * @log_p: if %TRUE, log of the result will be returned instead
475 * Returns: cumulative density of the log-normal distribution.
478 plnorm (gnm_float x
, gnm_float logmean
, gnm_float logsd
, gboolean lower_tail
, gboolean log_p
)
480 if (gnm_isnan (x
) || gnm_isnan (logmean
) || gnm_isnan (logsd
))
481 return x
+ logmean
+ logsd
;
487 ? pnorm (gnm_log (x
), logmean
, logsd
, lower_tail
, log_p
)
491 /* ------------------------------------------------------------------------ */
496 * @logmean: mean of the underlying normal distribution
497 * @logsd: standard deviation of the underlying normal distribution
498 * @lower_tail: if %TRUE, the lower tail of the distribution is considered.
499 * @log_p: if %TRUE, @p is given as log probability
501 * Returns: the observation with cumulative probability @p for the
502 * log-normal distribution.
505 qlnorm (gnm_float p
, gnm_float logmean
, gnm_float logsd
, gboolean lower_tail
, gboolean log_p
)
507 if (gnm_isnan (p
) || gnm_isnan (logmean
) || gnm_isnan (logsd
))
508 return p
+ logmean
+ logsd
;
510 if (log_p
? (p
> 0) : (p
< 0 || p
> 1))
513 return gnm_exp (qnorm (p
, logmean
, logsd
, lower_tail
, log_p
));
516 /* ------------------------------------------------------------------------ */
519 dcauchy1 (gnm_float x
, const gnm_float shape
[], gboolean give_log
)
521 return dcauchy (x
, shape
[0], shape
[1], give_log
);
525 pcauchy1 (gnm_float x
, const gnm_float shape
[], gboolean lower_tail
, gboolean log_p
)
527 return pcauchy (x
, shape
[0], shape
[1], lower_tail
, log_p
);
533 * @location: center of distribution
534 * @scale: scale parameter of the distribution
535 * @lower_tail: if %TRUE, the lower tail of the distribution is considered.
536 * @log_p: if %TRUE, @p is given as log probability
538 * Returns: the observation with cumulative probability @p for the
539 * Cauchy distribution.
543 qcauchy (gnm_float p
, gnm_float location
, gnm_float scale
,
544 gboolean lower_tail
, gboolean log_p
)
548 if (gnm_isnan(p
) || gnm_isnan(location
) || gnm_isnan(scale
))
549 return p
+ location
+ scale
;
551 if (log_p
? (p
> 0) : (p
< 0 || p
> 1))
554 if (scale
< 0 || !gnm_finite(scale
)) return gnm_nan
;
558 /* The "0" here is important for the p=0 case: */
559 lower_tail
= !lower_tail
, p
= 0 - gnm_expm1 (p
);
566 lower_tail
= !lower_tail
;
569 x
= location
+ (lower_tail
? -scale
: scale
) * gnm_cotpi (p
);
571 if (location
!= 0 && gnm_abs (x
/ location
) < 0.25) {
572 /* Cancellation has occurred. */
576 x
= pfuncinverter (p
, shape
, lower_tail
, log_p
,
577 gnm_ninf
, gnm_pinf
, x
,
585 /* ------------------------------------------------------------------------ */
588 phyper1 (gnm_float x
, const gnm_float shape
[],
589 gboolean lower_tail
, gboolean log_p
)
591 return phyper (x
, shape
[0], shape
[1], shape
[2], lower_tail
, log_p
);
595 qhyper (gnm_float p
, gnm_float NR
, gnm_float NB
, gnm_float n
,
596 gboolean lower_tail
, gboolean log_p
)
598 gnm_float y
, shape
[3];
599 gnm_float N
= NR
+ NB
;
601 if (gnm_isnan (p
) || gnm_isnan (N
) || gnm_isnan (n
))
603 if(!gnm_finite (p
) || !gnm_finite (N
) ||
604 NR
< 0 || NB
< 0 || n
< 0 || n
> N
)
612 gnm_float mu
= n
* NR
/ N
;
614 gnm_sqrt (NR
* NB
* n
* (N
- n
) / (N
* N
* (N
- 1)));
615 gnm_float sigma_gamma
=
616 (N
- 2 * NR
) * (N
- 2 * n
) / ((N
- 2) * N
);
618 /* Cornish-Fisher expansion: */
619 gnm_float z
= qnorm (p
, 0., 1., lower_tail
, log_p
);
620 y
= mu
+ sigma
* z
+ sigma_gamma
* (z
* z
- 1) / 6;
624 return discpfuncinverter (p
, shape
, lower_tail
, log_p
,
625 MAX (0, n
- NB
), MIN (n
, NR
), y
,
629 /* ------------------------------------------------------------------------ */
633 * @scale: scale parameter
634 * @give_log: if %TRUE, log of the result will be returned instead
636 * Returns: density of the Rayleigh distribution.
640 drayleigh (gnm_float x
, gnm_float scale
, gboolean give_log
)
642 // This is tempting, but has lower precision since sqrt(2)
645 // return dweibull (x, 2, M_SQRT2gnum * scale, give_log);
652 gnm_float p
= dnorm (x
, 0, scale
, give_log
);
654 ? p
+ gnm_log (x
/ scale
) + M_LN_SQRT_2PI
655 : p
* x
/ scale
* M_SQRT_2PI
;
659 /* ------------------------------------------------------------------------ */
663 * @scale: scale parameter
664 * @lower_tail: if %TRUE, the lower tail of the distribution is considered.
665 * @log_p: if %TRUE, log of the result will be returned instead
667 * Returns: cumulative density of the Rayleigh distribution.
671 prayleigh (gnm_float x
, gnm_float scale
, gboolean lower_tail
, gboolean log_p
)
673 return pweibull (x
, 2, M_SQRT2gnum
* scale
, lower_tail
, log_p
);
680 * @scale: scale parameter
681 * @lower_tail: if %TRUE, the lower tail of the distribution is considered.
682 * @log_p: if %TRUE, log of the result will be returned instead
684 * Returns: the observation with cumulative probability @p for the
685 * Rayleigh distribution.
688 qrayleigh (gnm_float p
, gnm_float scale
, gboolean lower_tail
, gboolean log_p
)
690 return qweibull (p
, 2, M_SQRT2gnum
* scale
, lower_tail
, log_p
);
693 /* ------------------------------------------------------------------------ */