[2c63e80e] | 1 | // Visit http://www.johndcook.com/stand_alone_code.html for the source of this code and more like it. |
---|
| 2 | // Modified for the DANSE project. |
---|
| 3 | |
---|
[2c041e9] | 4 | #include <math.h> |
---|
[2c63e80e] | 5 | |
---|
| 6 | #include "gamma_win.h" |
---|
| 7 | |
---|
| 8 | // Note that the functions Gamma and LogGamma are mutually dependent. |
---|
| 9 | |
---|
| 10 | double gamma(double x) |
---|
| 11 | { |
---|
| 12 | // Split the function domain into three intervals: |
---|
| 13 | // (0, 0.001), [0.001, 12), and (12, infinity) |
---|
| 14 | |
---|
| 15 | /////////////////////////////////////////////////////////////////////////// |
---|
| 16 | // First interval: (0, 0.001) |
---|
| 17 | // |
---|
| 18 | // For small x, 1/Gamma(x) has power series x + gamma x^2 - ... |
---|
| 19 | // So in this range, 1/Gamma(x) = x + gamma x^2 with error on the order of x^3. |
---|
| 20 | // The relative error over this interval is less than 6e-7. |
---|
| 21 | |
---|
| 22 | const double gamma = 0.577215664901532860606512090; // Euler's gamma constant |
---|
| 23 | double y; |
---|
| 24 | int arg_was_less_than_one = 0; |
---|
| 25 | int n = 0; |
---|
| 26 | // numerator coefficients for approximation over the interval (1,2) |
---|
| 27 | static const double p[] = |
---|
| 28 | { |
---|
| 29 | -1.71618513886549492533811E+0, |
---|
| 30 | 2.47656508055759199108314E+1, |
---|
| 31 | -3.79804256470945635097577E+2, |
---|
| 32 | 6.29331155312818442661052E+2, |
---|
| 33 | 8.66966202790413211295064E+2, |
---|
| 34 | -3.14512729688483675254357E+4, |
---|
| 35 | -3.61444134186911729807069E+4, |
---|
| 36 | 6.64561438202405440627855E+4 |
---|
| 37 | }; |
---|
| 38 | // denominator coefficients for approximation over the interval (1,2) |
---|
| 39 | static const double q[] = |
---|
| 40 | { |
---|
| 41 | -3.08402300119738975254353E+1, |
---|
| 42 | 3.15350626979604161529144E+2, |
---|
| 43 | -1.01515636749021914166146E+3, |
---|
| 44 | -3.10777167157231109440444E+3, |
---|
| 45 | 2.25381184209801510330112E+4, |
---|
| 46 | 4.75584627752788110767815E+3, |
---|
| 47 | -1.34659959864969306392456E+5, |
---|
| 48 | -1.15132259675553483497211E+5 |
---|
| 49 | }; |
---|
| 50 | double num = 0.0; |
---|
| 51 | double den = 1.0; |
---|
| 52 | int i; |
---|
| 53 | double z; |
---|
| 54 | double result; |
---|
| 55 | |
---|
| 56 | if (x < 0.001) |
---|
| 57 | return 1.0/(x*(1.0 + gamma*x)); |
---|
| 58 | |
---|
| 59 | /////////////////////////////////////////////////////////////////////////// |
---|
| 60 | // Second interval: [0.001, 12) |
---|
| 61 | |
---|
| 62 | if (x < 12.0) |
---|
| 63 | { |
---|
| 64 | // The algorithm directly approximates gamma over (1,2) and uses |
---|
| 65 | // reduction identities to reduce other arguments to this interval. |
---|
| 66 | |
---|
| 67 | y = x; |
---|
| 68 | |
---|
| 69 | if (y < 1.0) arg_was_less_than_one = 1; |
---|
| 70 | |
---|
| 71 | // Add or subtract integers as necessary to bring y into (1,2) |
---|
| 72 | // Will correct for this below |
---|
| 73 | if (arg_was_less_than_one==1) { |
---|
| 74 | y += 1.0; |
---|
| 75 | } else { |
---|
[3eac3816] | 76 | n = (int) (floor(y)) - 1; // will use n later |
---|
[2c63e80e] | 77 | y -= n; |
---|
| 78 | } |
---|
| 79 | |
---|
| 80 | z = y - 1; |
---|
| 81 | for (i = 0; i < 8; i++) { |
---|
| 82 | num = (num + p[i])*z; |
---|
| 83 | den = den*z + q[i]; |
---|
| 84 | } |
---|
| 85 | result = num/den + 1.0; |
---|
| 86 | |
---|
| 87 | // Apply correction if argument was not initially in (1,2) |
---|
| 88 | if (arg_was_less_than_one==1) { |
---|
| 89 | // Use identity gamma(z) = gamma(z+1)/z |
---|
| 90 | // The variable "result" now holds gamma of the original y + 1 |
---|
| 91 | // Thus we use y-1 to get back the orginal y. |
---|
| 92 | result /= (y-1.0); |
---|
| 93 | } else { |
---|
| 94 | // Use the identity gamma(z+n) = z*(z+1)* ... *(z+n-1)*gamma(z) |
---|
| 95 | for (i = 0; i < n; i++) |
---|
| 96 | result *= y++; |
---|
| 97 | } |
---|
| 98 | |
---|
| 99 | return result; |
---|
| 100 | } |
---|
| 101 | |
---|
| 102 | return exp(lgamma(x)); |
---|
| 103 | } |
---|
| 104 | |
---|
| 105 | double lgamma (double x) |
---|
| 106 | { |
---|
| 107 | static const double c[8] = |
---|
| 108 | { |
---|
| 109 | 1.0/12.0, |
---|
| 110 | -1.0/360.0, |
---|
| 111 | 1.0/1260.0, |
---|
| 112 | -1.0/1680.0, |
---|
| 113 | 1.0/1188.0, |
---|
| 114 | -691.0/360360.0, |
---|
| 115 | 1.0/156.0, |
---|
| 116 | -3617.0/122400.0 |
---|
| 117 | }; |
---|
| 118 | double z = 1.0/(x*x); |
---|
| 119 | double sum = c[7]; |
---|
| 120 | static const double halfLogTwoPi = 0.91893853320467274178032973640562; |
---|
| 121 | double series; |
---|
| 122 | double logGamma; |
---|
[1a31715] | 123 | int i; |
---|
[2c63e80e] | 124 | |
---|
| 125 | if (x < 12.0) { |
---|
| 126 | return log(fabs(gamma(x))); |
---|
| 127 | } |
---|
| 128 | |
---|
| 129 | // Abramowitz and Stegun 6.1.41 |
---|
| 130 | // Asymptotic series should be good to at least 11 or 12 figures |
---|
| 131 | // For error analysis, see Whittiker and Watson |
---|
| 132 | // A Course in Modern Analysis (1927), page 252 |
---|
| 133 | |
---|
[1a31715] | 134 | for (i=6; i >= 0; i--) { |
---|
[2c63e80e] | 135 | sum *= z; |
---|
| 136 | sum += c[i]; |
---|
| 137 | } |
---|
| 138 | series = sum/x; |
---|
| 139 | logGamma = (x - 0.5)*log(x) - x + halfLogTwoPi + series; |
---|
| 140 | return logGamma; |
---|
| 141 | } |
---|