Mercurial > hg > jslab
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>Γ( z ) = ∫<sub>0</sub><sup>∞</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>Γ( a, x ) = ∫<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> Γ( z ) = ∫<sub>0</sub><sup>∞</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( Γ( z ) ) = log ( ∫<sub>0</sub><sup>∞</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>Γ(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>Γ( a, x ) = ∫<sub>0</sub><sup>∞</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>Γ( a, x ) = ∫<sub>0</sub><sup>∞</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 |