1 #include <gnumeric-config.h>
9 /* ------------------------------------------------------------------------- */
11 /* The skew-normal distribution. */
14 dsnorm (gnm_float x
, gnm_float shape
, gnm_float location
, gnm_float scale
, gboolean give_log
)
16 if (gnm_isnan (x
) || gnm_isnan (shape
) || gnm_isnan (location
) || gnm_isnan (scale
))
20 return dnorm (x
, location
, scale
, give_log
);
22 return M_LN2gnum
+ dnorm (x
, location
, scale
, TRUE
) + pnorm (shape
* x
, shape
* location
, scale
, TRUE
, TRUE
);
24 return 2 * dnorm (x
, location
, scale
, FALSE
) * pnorm (shape
* x
, location
/shape
, scale
, TRUE
, FALSE
);
28 psnorm (gnm_float x
, gnm_float shape
, gnm_float location
, gnm_float scale
, gboolean lower_tail
, gboolean log_p
)
32 if (gnm_isnan (x
) || gnm_isnan (shape
) ||
33 gnm_isnan (location
) || gnm_isnan (scale
))
37 return pnorm (x
, location
, scale
, lower_tail
, log_p
);
40 h
= (x
- location
) / scale
;
42 /* Flip to a lower-tail problem. */
46 lower_tail
= !lower_tail
;
49 if (gnm_abs (shape
) < 10) {
50 gnm_float s
= pnorm (h
, 0, 1, lower_tail
, FALSE
);
51 gnm_float t
= 2 * gnm_owent (h
, shape
);
55 * Make use of this result for Owen's T:
57 * T(h,a) = .5N(h) + .5N(ha) - N(h)N(ha) - T(ha,1/a)
59 gnm_float s
= pnorm (h
* shape
, 0, 1, TRUE
, FALSE
);
60 gnm_float u
= gnm_erf (h
/ M_SQRT2gnum
);
61 gnm_float t
= 2 * gnm_owent (h
* shape
, 1 / shape
);
66 * Negatives can occur due to rounding errors and hopefully for no
69 result
= CLAMP (result
, 0.0, 1.0);
72 return gnm_log (result
);
78 dsnorm1 (gnm_float x
, const gnm_float params
[], gboolean log_p
)
80 return dsnorm (x
, params
[0], params
[1], params
[2], log_p
);
84 psnorm1 (gnm_float x
, const gnm_float params
[],
85 gboolean lower_tail
, gboolean log_p
)
87 return psnorm (x
, params
[0], params
[1], params
[2], lower_tail
, log_p
);
91 qsnorm (gnm_float p
, gnm_float shape
, gnm_float location
, gnm_float scale
,
92 gboolean lower_tail
, gboolean log_p
)
97 if (gnm_isnan (p
) || gnm_isnan (shape
) || gnm_isnan (location
) || gnm_isnan (scale
))
101 return qnorm (p
, location
, scale
, lower_tail
, log_p
);
103 if (!log_p
&& p
> 0.9) {
104 /* We're far into the tail. Flip. */
106 lower_tail
= !lower_tail
;
111 params
[1] = location
;
113 return pfuncinverter (p
, params
, lower_tail
, log_p
,
114 gnm_ninf
, gnm_pinf
, x0
,
118 /* ------------------------------------------------------------------------- */
120 /* The skew-t distribution. */
123 dst (gnm_float x
, gnm_float n
, gnm_float shape
, gboolean give_log
)
125 if (n
<= 0 || gnm_isnan (x
) || gnm_isnan (n
) || gnm_isnan (shape
))
129 return dt (x
, n
, give_log
);
131 gnm_float pdf
= dt (x
, n
, give_log
);
132 gnm_float cdf
= pt (shape
* x
* gnm_sqrt ((n
+ 1)/(x
* x
+ n
)),
133 n
+ 1, TRUE
, give_log
);
134 return give_log
? (M_LN2gnum
+ pdf
+ cdf
) : (2. * pdf
* cdf
);
139 gnm_atan_mpihalf (gnm_float x
)
142 return gnm_acot (-x
);
144 return gnm_atan (x
) - (M_PIgnum
/ 2);
148 pst (gnm_float x
, gnm_float n
, gnm_float shape
, gboolean lower_tail
, gboolean log_p
)
152 if (n
<= 0 || gnm_isnan (x
) || gnm_isnan (n
) || gnm_isnan (shape
))
156 return pt (x
, n
, lower_tail
, log_p
);
160 return psnorm (x
, shape
, 0.0, 1.0, lower_tail
, log_p
);
163 /* Flip to a lower-tail problem. */
167 lower_tail
= !lower_tail
;
170 /* Generic fallback. */
172 gnm_log (pst (x
, n
, shape
, TRUE
, FALSE
));
174 if (n
!= gnm_floor (n
)) {
175 /* We would need numerical integration for this. */
180 * Use recurrence formula from "Recurrent relations for
181 * distributions of a skew-t and a linear combination of order
182 * statistics form a bivariate-t", Computational Statistics
183 * and Data Analysis volume 52, 2009 by Jamallizadeh,
184 * Khosravi, Balakrishnan.
186 * This brings us down to n==1 or n==2 for which explicit formulas
192 double a
, lb
, c
, d
, pv
, v
= n
- 1;
195 ? M_LN2gnum
- gnm_log (M_PIgnum
) + gnm_log (3) / 2
196 : (0.5 + M_LN2gnum
/ 2 - gnm_log (M_PIgnum
) / 2 +
197 v
/ 2 * (gnm_log1p (-1 / (v
- 1)) + gnm_log (v
+ 1)) -
198 0.5 * (gnm_log (v
- 2) + gnm_log (v
+ 1)) +
199 stirlerr (v
/ 2 - 1) -
200 stirlerr ((v
- 1) / 2));
203 lb
= (d
- gnm_log (a
) * v
/ 2);
204 c
= pt (gnm_sqrt (v
) * shape
* x
/ gnm_sqrt (a
), v
, TRUE
, FALSE
);
205 pv
= x
* gnm_exp (lb
) * c
;
209 x
*= gnm_sqrt ((v
- 1) / (v
+ 1));
212 g_return_val_if_fail (n
== 1 || n
== 2, gnm_nan
);
216 p1
= (gnm_atan (x
) + gnm_acos (shape
/ gnm_sqrt ((1 + shape
* shape
) * (1 + x
* x
)))) / M_PIgnum
;
221 f
= x
/ gnm_sqrt (2 + x
* x
);
223 p2
= (gnm_atan_mpihalf (shape
) + f
* gnm_atan_mpihalf (-shape
* f
)) / -M_PIgnum
;
231 * Negatives can occur due to rounding errors and hopefully for no
234 p
= CLAMP (p
, 0.0, 1.0);
241 dst1 (gnm_float x
, const gnm_float params
[], gboolean log_p
)
243 return dst (x
, params
[0], params
[1], log_p
);
247 pst1 (gnm_float x
, const gnm_float params
[],
248 gboolean lower_tail
, gboolean log_p
)
250 return pst (x
, params
[0], params
[1], lower_tail
, log_p
);
254 qst (gnm_float p
, gnm_float n
, gnm_float shape
,
255 gboolean lower_tail
, gboolean log_p
)
260 if (n
<= 0 || gnm_isnan (p
) || gnm_isnan (n
) || gnm_isnan (shape
))
264 return qt (p
, n
, lower_tail
, log_p
);
266 if (!log_p
&& p
> 0.9) {
267 /* We're far into the tail. Flip. */
269 lower_tail
= !lower_tail
;
275 return pfuncinverter (p
, params
, lower_tail
, log_p
,
276 gnm_ninf
, gnm_pinf
, x0
,
280 /* ------------------------------------------------------------------------- */
283 dgumbel (gnm_float x
, gnm_float mu
, gnm_float beta
, gboolean give_log
)
287 if (!(beta
> 0) || gnm_isnan (mu
) || gnm_isnan (beta
) || gnm_isnan (x
))
291 lp
= -(z
+ gnm_exp (-z
));
292 return give_log
? lp
- gnm_log (beta
) : gnm_exp (lp
) / beta
;
296 pgumbel (gnm_float x
, gnm_float mu
, gnm_float beta
, gboolean lower_tail
, gboolean log_p
)
300 if (!(beta
> 0) || gnm_isnan (mu
) || gnm_isnan (beta
) || gnm_isnan (x
))
306 return log_p
? lp
: gnm_exp (lp
);
308 return log_p
? swap_log_tail (lp
) : 0 - gnm_expm1 (lp
);
312 qgumbel (gnm_float p
, gnm_float mu
, gnm_float beta
, gboolean lower_tail
, gboolean log_p
)
315 gnm_isnan (mu
) || gnm_isnan (beta
) || gnm_isnan (p
) ||
316 (log_p
? p
> 0 : (p
< 0 || p
> 1)))
321 p
= swap_log_tail (p
);
329 /* We're now in the log_p, lower_tail case. */
330 return mu
- beta
* gnm_log (-p
);