SDDSlib
Loading...
Searching...
No Matches
gammai.c
Go to the documentation of this file.
1/**
2 * @file gammai.c
3 * @brief Routines for computing the incomplete gamma functions.
4 *
5 * @copyright
6 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
7 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
8 *
9 * @license
10 * This file is distributed under the terms of the Software License Agreement
11 * found in the file LICENSE included with this distribution.
12 *
13 * @author M. Borland, C. Saunders, R. Soliday
14 */
15
16#include "mdb.h"
17
18#if defined(_WIN32)
19# if _MSC_VER <= 1600
20# include "fdlibm.h"
21# endif
22#endif
23
24double gammaIncSeries(double a, double x);
25double gammaIncCFrac(double a, double x);
26
27#define GAMMAI_ACCURACY 1e-12
28
29/**
30 * @brief Compute the regularized lower incomplete gamma function P(a,x).
31 *
32 * For given parameters a > 0 and x ≥ 0, this function returns the value of P(a,x) = γ(a,x)/Γ(a),
33 * where γ(a,x) is the lower incomplete gamma function. Uses series expansion for x < a+1,
34 * and a continued fraction expansion otherwise.
35 *
36 * @param a Shape parameter (a > 0).
37 * @param x The upper limit of the integral (x ≥ 0).
38 * @return The value of P(a,x), or -1 if inputs are invalid.
39 */
40double gammaP(double a, double x) {
41 if (a <= 0 || x < 0)
42 return -1;
43 if (x == 0)
44 return 0;
45 if (x < a + 1) {
46 /* use series */
47 return gammaIncSeries(a, x);
48 } else {
49 /* use continued fraction */
50 return 1 - gammaIncCFrac(a, x);
51 }
52}
53
54/**
55 * @brief Compute the regularized upper incomplete gamma function Q(a,x).
56 *
57 * For given parameters a > 0 and x ≥ 0, this function returns Q(a,x) = 1 - P(a,x).
58 * It uses a series expansion when x < a+1 and a continued fraction expansion otherwise.
59 *
60 * @param a Shape parameter (a > 0).
61 * @param x The upper limit of the integral (x ≥ 0).
62 * @return The value of Q(a,x), or -1 if inputs are invalid.
63 */
64double gammaQ(double a, double x) {
65 if (a <= 0 || x < 0)
66 return -1;
67 if (x == 0)
68 return 0;
69 if (x < a + 1) {
70 /* use series */
71 return 1 - gammaIncSeries(a, x);
72 } else {
73 /* use continued fraction */
74 return gammaIncCFrac(a, x);
75 }
76}
77
78#define MAX_SERIES 1000
79
80double gammaIncSeries(double a, double x) {
81 double term = 0, sum;
82 long n;
83#if defined(vxWorks)
84 fprintf(stderr, "lgamma function not implemented in vxWorks");
85 exit(1);
86#else
87 term = exp(-x) * pow(x, a) / exp(lgamma(a + 1));
88#endif
89 sum = 0;
90 n = 0;
91 do {
92 sum += term;
93 n++;
94 term *= x / (a + n);
95 } while (term > GAMMAI_ACCURACY && n < MAX_SERIES);
96 return (sum + term);
97}
98
99double gammaIncCFrac(double a, double x) {
100 double A0, B0, A1, B1, A_1, B_1;
101 double an, bn, f1, f2, accuracy = 0, factor = 0;
102 long m;
103
104#if defined(vxWorks)
105 fprintf(stderr, "lgamma function not implemented in vxWorks");
106 exit(1);
107#else
108 accuracy = GAMMAI_ACCURACY / (factor = exp(-x - lgamma(a) + a * log(x)));
109#endif
110 A0 = 0;
111 B0 = 1;
112 A_1 = 1;
113 B_1 = 0;
114 an = 1;
115 bn = x + 1 - a;
116 A1 = bn * A0 + an * A_1;
117 B1 = bn * B0 + an * B_1;
118 f2 = A1 / B1;
119 m = 1;
120 do {
121 A_1 = A0;
122 B_1 = B0;
123 A0 = A1;
124 B0 = B1;
125 f1 = f2;
126 an = -m * (m - a);
127 bn += 2;
128 A1 = bn * A0 + an * A_1;
129 B1 = bn * B0 + an * B_1;
130 f2 = A1 / B1;
131 if (B1) {
132 /* rescale the recurrence to avoid over/underflow */
133 A0 /= B1;
134 B0 /= B1;
135 A1 /= B1;
136 B1 = 1;
137 }
138 m++;
139 } while (m < MAX_SERIES && fabs(f1 - f2) > accuracy);
140 return factor * f2;
141}
double gammaP(double a, double x)
Compute the regularized lower incomplete gamma function P(a,x).
Definition gammai.c:40
double gammaQ(double a, double x)
Compute the regularized upper incomplete gamma function Q(a,x).
Definition gammai.c:64