1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.irurueta.statistics;
18
19
20
21
22
23
24
25
26 public class Gamma extends GaussLegendreQuadrature {
27
28
29
30
31 protected static final int MAX_CACHED_LOG_FACTORIALS = 2000;
32
33
34
35
36 private static final int ASWITCH = 100;
37
38
39
40
41 private static final double EPS = Math.ulp(1.0);
42
43
44
45
46 private static final double FPMIN = Double.MIN_VALUE / EPS;
47
48
49
50
51 private static final int MAX_FACTORIALS = 170;
52
53
54
55
56 private static final int DEFAULT_MAX_ITERATIONS = 100;
57
58
59
60
61 private static final double[] COF = {57.1562356658629235, -59.5979603554754912,
62 14.1360979747417471, -0.491913816097620199, .339946499848118887e-4,
63 .465236289270485756e-4, -.983744753048795646e-4, .158088703224912494e-3,
64 -.210264441724104883e-3, .217439618115212643e-3, -.164318106536763890e-3,
65 .844182239838527433e-4, -.261908384015814087e-4, .368991826595316234e-5};
66
67
68
69
70
71 private static boolean factorialsInitialized;
72
73
74
75
76 private static double[] factorialsTable;
77
78
79
80
81
82 private static boolean logarithmOfFactorialsInitialized;
83
84
85
86
87 private static double[] logarithmOfFactorialsTable;
88
89
90
91
92 private double gln;
93
94
95
96
97
98
99 public double getGln() {
100 return gln;
101 }
102
103
104
105
106
107
108
109
110 public static double gammln(final double xx) {
111 if (xx <= 0.0) {
112 throw new IllegalArgumentException("bad arg in gammln");
113 }
114
115 int j;
116 double x;
117 double tmp;
118 double y;
119 double ser;
120
121 y = x = xx;
122 tmp = x + 5.24218750000000000;
123 tmp = (x + 0.5) * Math.log(tmp) - tmp;
124 ser = 0.999999999999997092;
125 for (j = 0; j < 14; j++) {
126 ser += COF[j] / ++y;
127 }
128 return tmp + Math.log(2.5066282746310005 * ser / x);
129 }
130
131
132
133
134
135
136
137
138
139
140
141
142
143 public static double factrl(final int n) {
144 if (n < 0 || n > MAX_FACTORIALS) {
145 throw new IllegalArgumentException("factrl out of range");
146 }
147
148 if (!factorialsInitialized) {
149 factorialsInitialized = true;
150 factorialsTable = new double[171];
151 factorialsTable[0] = 1.;
152 for (int i = 1; i < (MAX_FACTORIALS + 1); i++) {
153 factorialsTable[i] = i * factorialsTable[i - 1];
154 }
155 }
156
157 return factorialsTable[n];
158 }
159
160
161
162
163
164
165
166
167 public static double factln(final int n) {
168 if (n < 0) {
169 throw new IllegalArgumentException("negative arg in factln");
170 }
171
172 if (!logarithmOfFactorialsInitialized) {
173 logarithmOfFactorialsInitialized = true;
174 logarithmOfFactorialsTable = new double[MAX_CACHED_LOG_FACTORIALS];
175 for (int i = 0; i < MAX_CACHED_LOG_FACTORIALS; i++) {
176 logarithmOfFactorialsTable[i] = gammln(i + 1.);
177 }
178 }
179 if (n < MAX_CACHED_LOG_FACTORIALS) {
180 return logarithmOfFactorialsTable[n];
181 }
182 return gammln(n + 1.);
183 }
184
185
186
187
188
189
190
191
192
193
194
195 public static double bico(final int n, final int k) {
196 if (k < 0 || k > n) {
197 throw new IllegalArgumentException("bad args in bico");
198 }
199
200 if (n < MAX_FACTORIALS + 1) {
201 return Math.floor(0.5 + factrl(n) / (factrl(k) * factrl(n - k)));
202 }
203
204
205
206 return Math.floor(0.5 + Math.exp(factln(n) - factln(k) - factln(n - k)));
207 }
208
209
210
211
212
213
214
215
216
217 public static double beta(final double z, final double w) {
218 return Math.exp(gammln(z) + gammln(w) - gammln(z + w));
219 }
220
221
222
223
224
225
226
227
228
229
230 public double gammp(final double a, final double x) throws MaxIterationsExceededException {
231 if (x < 0.0 || a <= 0.0) {
232 throw new IllegalArgumentException("bad args in gammp");
233 }
234
235 if (x == 0.0) {
236 return 0.0;
237 } else if ((int) a >= ASWITCH) {
238 return gammpapprox(a, x, 1);
239 } else if (x < a + 1.0) {
240 return gser(a, x);
241 } else {
242 return 1.0 - gcf(a, x);
243 }
244 }
245
246
247
248
249
250
251
252
253
254
255 public double gammq(final double a, final double x) throws MaxIterationsExceededException {
256 if (x < 0.0 || a <= 0.0) {
257 throw new IllegalArgumentException("bad args in gammq");
258 }
259
260 if (x == 0.0) {
261 return 1.0;
262 } else if ((int) a >= ASWITCH) {
263 return gammpapprox(a, x, 0);
264 } else if (x < a + 1.0) {
265 return 1.0 - gser(a, x);
266 } else {
267 return gcf(a, x);
268 }
269 }
270
271
272
273
274
275
276
277
278
279
280
281 private double gser(final double a, final double x) throws MaxIterationsExceededException {
282 return gser(a, x, DEFAULT_MAX_ITERATIONS);
283 }
284
285
286
287
288
289
290
291
292
293
294
295
296 @SuppressWarnings("SameParameterValue")
297 private double gser(final double a, final double x, final int maxIterations) throws MaxIterationsExceededException {
298 double sum;
299 double del;
300 double ap;
301
302 gln = gammln(a);
303 ap = a;
304 del = sum = 1.0 / a;
305 for (; ; ) {
306 ++ap;
307 del *= x / ap;
308 sum += del;
309 if (Math.abs(del) < Math.abs(sum) * EPS) {
310 return sum * Math.exp(-x + a * Math.log(x) - gln);
311 }
312
313 if (ap >= maxIterations) {
314 throw new MaxIterationsExceededException();
315 }
316 }
317 }
318
319
320
321
322
323
324
325
326
327
328
329 private double gcf(final double a, final double x) throws MaxIterationsExceededException {
330 return gcf(a, x, DEFAULT_MAX_ITERATIONS);
331 }
332
333
334
335
336
337
338
339
340
341
342
343
344 @SuppressWarnings("SameParameterValue")
345 private double gcf(final double a, final double x, final int maxIterations) throws MaxIterationsExceededException {
346 int i;
347 double an;
348 double b;
349 double c;
350 double d;
351 double del;
352 double h;
353 gln = gammln(a);
354 b = x + 1.0 - a;
355 c = 1.0 / FPMIN;
356 d = 1.0 / b;
357 h = d;
358 for (i = 1; ; i++) {
359 an = -i * (i - a);
360 b += 2.0;
361 d = an * d + b;
362 if (Math.abs(d) < FPMIN) {
363 d = FPMIN;
364 }
365 c = b + an / c;
366 if (Math.abs(c) < FPMIN) {
367 c = FPMIN;
368 }
369 d = 1.0 / d;
370 del = d * c;
371 h *= del;
372 if (Math.abs(del - 1.0) <= EPS) {
373 break;
374 }
375 if (i >= maxIterations) {
376 throw new MaxIterationsExceededException();
377 }
378 }
379 return Math.exp(-x + a * Math.log(x) - gln) * h;
380 }
381
382
383
384
385
386
387
388
389
390
391 private double gammpapprox(final double a, final double x, final int psig) {
392 int j;
393 final double xu;
394 double t;
395 double sum;
396 final double ans;
397 final double a1 = a - 1.0;
398 final double lna1 = Math.log(a1);
399 final double sqrta1 = Math.sqrt(a1);
400 gln = gammln(a);
401 if (x > a1) {
402 xu = Math.max(a1 + 11.5 * sqrta1, x + 6.0 * sqrta1);
403 } else {
404 xu = Math.max(0., Math.min(a1 - 7.5 * sqrta1, x - 5.0 * sqrta1));
405 }
406 sum = 0;
407 for (j = 0; j < N_GAU; j++) {
408 t = x + (xu - x) * Y[j];
409 sum += W[j] * Math.exp(-(t - a1) + a1 * (Math.log(t) - lna1));
410 }
411 ans = sum * (xu - x) * Math.exp(a1 * (lna1 - 1.) - gln);
412
413 if (psig != 0) {
414 return ans > 0.0 ? 1.0 - ans : -ans;
415 } else {
416 return ans >= 0.0 ? ans : 1.0 + ans;
417 }
418 }
419
420
421
422
423
424
425
426
427
428
429
430
431 public double invgammp(final double p, final double a) throws MaxIterationsExceededException {
432 int j;
433 double x;
434 double err;
435 double t;
436 double u;
437 final double pp;
438 double lna1 = 0.0;
439 double afac = 0.0;
440 final double a1 = a - 1.0;
441 gln = gammln(a);
442 if (a <= 0.) {
443 throw new IllegalArgumentException("a must be pos in invgammap");
444 }
445 if (p >= 1.) {
446 return Math.max(100., a + 100. * Math.sqrt(a));
447 }
448 if (p <= 0.) {
449 return 0.0;
450 }
451 if (a > 1.) {
452 lna1 = Math.log(a1);
453 afac = Math.exp(a1 * (lna1 - 1.) - gln);
454 pp = p < 0.5 ? p : 1. - p;
455 t = Math.sqrt(-2. * Math.log(pp));
456 x = (2.30753 + t * 0.27061) / (1. + t * (0.99229 + t * 0.04481)) - t;
457 if (p < 0.5) {
458 x = -x;
459 }
460 x = Math.max(1.e-3, a * Math.pow(1. - 1. / (9. * a) - x / (3. * Math.sqrt(a)), 3));
461 } else {
462 t = 1.0 - a * (0.253 + a * 0.12);
463 if (p < t) {
464 x = Math.pow(p / t, 1. / a);
465 } else {
466 x = 1. - Math.log(1. - (p - t) / (1. - t));
467 }
468 }
469 for (j = 0; j < 12; j++) {
470 if (x <= 0.0) {
471 return 0.0;
472 }
473 err = gammp(a, x) - p;
474 if (a > 1.) {
475 t = afac * Math.exp(-(x - a1) + a1 * (Math.log(x) - lna1));
476 } else {
477 t = Math.exp(-x + a1 * Math.log(x) - gln);
478 }
479 u = err / t;
480 x -= (t = u / (1. - 0.5 * Math.min(1., u * ((a - 1.) / x - 1))));
481 if (x <= 0.) {
482 x = 0.5 * (x + t);
483 }
484 if (Math.abs(t) < EPS * x) {
485 break;
486 }
487 }
488 return x;
489 }
490 }