comparison src/samer/functions/Gamma.java @ 0:bf79fb79ee13

Initial Mercurial check in.
author samer
date Tue, 17 Jan 2012 17:50:20 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:bf79fb79ee13
1 // JEM - Java tools for Experimental Mathematics
2 // Copyright (C) 2001 JEM-Group
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18 package samer.functions;
19
20 /**
21 * Implementation of the real (incomplete) Gamma function.
22 * <p>
23 * This class provides an implementaion of the real Gamma function
24 * <p align=center>
25 * <code>&Gamma;( z ) = &int;<sub>0</sub><sup>&infin;</sup> t<sup>z-1</sup>e<sup>-t</sup>dt</code>
26 * </p>
27 * and its sibling, the <i>incomplete</i> Gamma function:
28 * <p align=center>
29 * <code>&Gamma;( a, x ) = &int;<sub>0</sub><sup>x</sup>t<sup>a-1</sup>e<sup>-t</sup>dt</code>
30 * </p><p>
31 * The Implementation follows the ideas of C.Lanczos and their realizations
32 * presented in <em>Numerical Recipes in C</em>.
33 * </p><p>
34 * Further reading:
35 * <table>
36 * <tr><td> - </td><td>C.Lanczos, 1964, SIAM Journal of Numerical Analysis, ser. B, vol. 1,
37 * pp. 86-96.</td></tr>
38 * <tr><td> - </td><td>W.H.Press, S.A.Teukolsky, W.T.Vetterling, B.P.Flannery.
39 * <em>Numerical Recipes in C</em>. Cambridge University Press, 1992. </td></tr>
40 * </table>
41 *</p>
42 */
43 public class Gamma {
44
45 private static final double a = Math.sqrt( 2*Math.PI ) * 1.000000000190015;
46 private static final double b = Math.sqrt( 2*Math.PI ) * 76.18009172947146;
47 private static final double c = Math.sqrt( 2*Math.PI ) * -86.50532032941677;
48 private static final double d = Math.sqrt( 2*Math.PI ) * 24.01409824083091;
49 private static final double e = Math.sqrt( 2*Math.PI ) * -1.231739572450155;
50 private static final double f = Math.sqrt( 2*Math.PI ) * 0.1208650973866179e-2;
51 private static final double g = Math.sqrt( 2*Math.PI ) * -0.5395239384953e-5;
52
53 private Gamma() {}
54
55 static double gamma_( double z ) {
56
57 if( z <= 0 )
58 throw new IllegalArgumentException("argument must be positive");
59
60 double s = Math.exp( Math.log( z + 5.5 ) * ( z + 0.5 ) - ( z + 5.5 ) );
61
62 return s * ( a +
63 b/(z+1) + c/(z+2) + d/(z+3) +
64 e/(z+4) + f/(z+5) + g/(z+6) ) / z;
65 }
66
67 /**
68 * Retunrs the gamma function at <code>z</code>.
69 * @param z a real number
70 * @return <code> &Gamma;( z ) = &int;<sub>0</sub><sup>&infin;</sup>
71 * t<sup>z-1</sup>e<sup>-t</sup>dt</code>
72 */
73 public static double gamma( double z ) {
74
75 return z <= 0.5 ? Math.PI / gamma_ ( 1 - z ) / Math.sin( Math.PI * z ) : gamma_ ( z );
76 }
77
78 static double logOfGamma_( double z ) {
79
80 if( z <= 0 )
81 throw new IllegalArgumentException("argument must be positive");
82
83 double s = Math.log( z + 5.5 ) * ( z + 0.5 ) - ( z + 5.5 );
84
85 return s + Math.log( ( a +
86 b/(z+1) + c/(z+2) + d/(z+3) +
87 e/(z+4) + f/(z+5) + g/(z+6) ) / z );
88 }
89
90
91 /**
92 * Retunrs the logarithm of the gamma function at <code>z</code>.
93 * @param z a real number
94 * @return <code>log( &Gamma;( z ) ) = log ( &int;<sub>0</sub><sup>&infin;</sup>
95 * t<sup>z-1</sup>e<sup>-t</sup>dt )</code>
96 */
97 public static double logOfGamma( double z ) {
98
99 return z <= 0.5
100 ? Math.log( Math.PI / Math.sin( Math.PI * z ) ) - logOfGamma_ ( 1 - z )
101 : logOfGamma_ ( z );
102
103 }
104
105
106 private static double gamma( double a, double x, double gammaOfA, boolean computeGammaOfA ) {
107
108 if( a<=0 )
109 throw new IllegalArgumentException( "a is not positive" );
110
111 if( x<0 )
112 throw new IllegalArgumentException( "x is negative" );
113
114 if( x < a + 1 ) {
115 if( computeGammaOfA )
116 gammaOfA = gamma ( a );
117
118 return computeViaSeries( a, x, gammaOfA );
119
120 } else
121 return computeViaContinuedFraction( a, x );
122 }
123
124 /**
125 * Returns the incomplete gamma function at <code>a, x</code>.
126 * The algorithms for the incomplete gamma function needs
127 * to compute <code>&Gamma;(a)</code>; providing this value
128 * will therefor lead to an optimization if you need
129 * this value also for a diffrent porpuse.
130 * @param a a positive real number
131 * @param x a real number greater than <code>a</code>
132 * @return <code>&Gamma;( a, x ) = &int;<sub>0</sub><sup>&infin;</sup>
133 * t<sup>z-1</sup>e<sup>-t</sup>dt</code>
134 */
135 public static double gamma( double a, double x, double gammaOfA ) {
136 return gamma ( a, x, gammaOfA, false );
137 }
138
139
140 /**
141 * Returns the incomplete gamma function at <code>a, x</code>.
142 * @param a a positive real number
143 * @param x a real number greater than <code>a</code>
144 * @return <code>&Gamma;( a, x ) = &int;<sub>0</sub><sup>&infin;</sup>
145 * t<sup>z-1</sup>e<sup>-t</sup>dt</code>
146 */
147 public static double gamma( double a, double x ) {
148 return gamma ( a, x, 123, true );
149 }
150
151 static int MAX_NUMBER_OF_ITERATIONS = 200;
152
153 static double EPS = 1e-16;
154
155 static double computeViaSeries( double a, double x, double gammaOfA ) {
156
157 double factor = a;
158 double delta = 1 / a;
159 double sum = delta;
160
161 int counter = 0;
162
163 while( Math.abs(delta) > Math.abs( sum ) * EPS ) {
164
165 delta *= x/++factor;
166
167 sum += delta;
168
169 if( counter > MAX_NUMBER_OF_ITERATIONS )
170 throw new RuntimeException( "exeeded max number of iterations="+
171 MAX_NUMBER_OF_ITERATIONS );
172 }
173
174 return gammaOfA - sum * Math.exp( a*Math.log( x ) - x );
175 }
176
177 static double MIN_DP = 1e-30;
178
179 static double computeViaContinuedFraction( double a, double x ) {
180
181 double b = x + 1 - a;
182 double c = 1/MIN_DP;
183 double d = 1/b;
184 double h = d;
185
186 for( int i=1; i<MAX_NUMBER_OF_ITERATIONS; i++ ) {
187
188 double an = -i * (i-a);
189
190 b += 2;
191
192 d = an*d + b;
193 c = an/c + b;
194
195 if( Math.abs( c ) < MIN_DP )
196 c = MIN_DP;
197 if( Math.abs( d ) < MIN_DP )
198 d = MIN_DP;
199
200 d = 1 / d;
201
202 double delta = c * d;
203
204 h *= delta;
205
206 if( Math.abs( delta - 1 ) < EPS )
207 return h * Math.exp( a * Math.log( x ) - x );
208 }
209
210 throw new RuntimeException( "exeeded max number of iterations="+
211 MAX_NUMBER_OF_ITERATIONS );
212 }
213
214 }
215