Mercurial > hg > jslab
view src/samer/functions/Gamma.java @ 5:b67a33c44de7
Remove some crap, etc
author | samer |
---|---|
date | Fri, 05 Apr 2019 21:34:25 +0100 |
parents | bf79fb79ee13 |
children |
line wrap: on
line source
// JEM - Java tools for Experimental Mathematics // Copyright (C) 2001 JEM-Group // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA package samer.functions; /** * Implementation of the real (incomplete) Gamma function. * <p> * This class provides an implementaion of the real Gamma function * <p align=center> * <code>Γ( z ) = ∫<sub>0</sub><sup>∞</sup> t<sup>z-1</sup>e<sup>-t</sup>dt</code> * </p> * and its sibling, the <i>incomplete</i> Gamma function: * <p align=center> * <code>Γ( a, x ) = ∫<sub>0</sub><sup>x</sup>t<sup>a-1</sup>e<sup>-t</sup>dt</code> * </p><p> * The Implementation follows the ideas of C.Lanczos and their realizations * presented in <em>Numerical Recipes in C</em>. * </p><p> * Further reading: * <table> * <tr><td> - </td><td>C.Lanczos, 1964, SIAM Journal of Numerical Analysis, ser. B, vol. 1, * pp. 86-96.</td></tr> * <tr><td> - </td><td>W.H.Press, S.A.Teukolsky, W.T.Vetterling, B.P.Flannery. * <em>Numerical Recipes in C</em>. Cambridge University Press, 1992. </td></tr> * </table> *</p> */ public class Gamma { private static final double a = Math.sqrt( 2*Math.PI ) * 1.000000000190015; private static final double b = Math.sqrt( 2*Math.PI ) * 76.18009172947146; private static final double c = Math.sqrt( 2*Math.PI ) * -86.50532032941677; private static final double d = Math.sqrt( 2*Math.PI ) * 24.01409824083091; private static final double e = Math.sqrt( 2*Math.PI ) * -1.231739572450155; private static final double f = Math.sqrt( 2*Math.PI ) * 0.1208650973866179e-2; private static final double g = Math.sqrt( 2*Math.PI ) * -0.5395239384953e-5; private Gamma() {} static double gamma_( double z ) { if( z <= 0 ) throw new IllegalArgumentException("argument must be positive"); double s = Math.exp( Math.log( z + 5.5 ) * ( z + 0.5 ) - ( z + 5.5 ) ); return s * ( a + b/(z+1) + c/(z+2) + d/(z+3) + e/(z+4) + f/(z+5) + g/(z+6) ) / z; } /** * Retunrs the gamma function at <code>z</code>. * @param z a real number * @return <code> Γ( z ) = ∫<sub>0</sub><sup>∞</sup> * t<sup>z-1</sup>e<sup>-t</sup>dt</code> */ public static double gamma( double z ) { return z <= 0.5 ? Math.PI / gamma_ ( 1 - z ) / Math.sin( Math.PI * z ) : gamma_ ( z ); } static double logOfGamma_( double z ) { if( z <= 0 ) throw new IllegalArgumentException("argument must be positive"); double s = Math.log( z + 5.5 ) * ( z + 0.5 ) - ( z + 5.5 ); return s + Math.log( ( a + b/(z+1) + c/(z+2) + d/(z+3) + e/(z+4) + f/(z+5) + g/(z+6) ) / z ); } /** * Retunrs the logarithm of the gamma function at <code>z</code>. * @param z a real number * @return <code>log( Γ( z ) ) = log ( ∫<sub>0</sub><sup>∞</sup> * t<sup>z-1</sup>e<sup>-t</sup>dt )</code> */ public static double logOfGamma( double z ) { return z <= 0.5 ? Math.log( Math.PI / Math.sin( Math.PI * z ) ) - logOfGamma_ ( 1 - z ) : logOfGamma_ ( z ); } private static double gamma( double a, double x, double gammaOfA, boolean computeGammaOfA ) { if( a<=0 ) throw new IllegalArgumentException( "a is not positive" ); if( x<0 ) throw new IllegalArgumentException( "x is negative" ); if( x < a + 1 ) { if( computeGammaOfA ) gammaOfA = gamma ( a ); return computeViaSeries( a, x, gammaOfA ); } else return computeViaContinuedFraction( a, x ); } /** * Returns the incomplete gamma function at <code>a, x</code>. * The algorithms for the incomplete gamma function needs * to compute <code>Γ(a)</code>; providing this value * will therefor lead to an optimization if you need * this value also for a diffrent porpuse. * @param a a positive real number * @param x a real number greater than <code>a</code> * @return <code>Γ( a, x ) = ∫<sub>0</sub><sup>∞</sup> * t<sup>z-1</sup>e<sup>-t</sup>dt</code> */ public static double gamma( double a, double x, double gammaOfA ) { return gamma ( a, x, gammaOfA, false ); } /** * Returns the incomplete gamma function at <code>a, x</code>. * @param a a positive real number * @param x a real number greater than <code>a</code> * @return <code>Γ( a, x ) = ∫<sub>0</sub><sup>∞</sup> * t<sup>z-1</sup>e<sup>-t</sup>dt</code> */ public static double gamma( double a, double x ) { return gamma ( a, x, 123, true ); } static int MAX_NUMBER_OF_ITERATIONS = 200; static double EPS = 1e-16; static double computeViaSeries( double a, double x, double gammaOfA ) { double factor = a; double delta = 1 / a; double sum = delta; int counter = 0; while( Math.abs(delta) > Math.abs( sum ) * EPS ) { delta *= x/++factor; sum += delta; if( counter > MAX_NUMBER_OF_ITERATIONS ) throw new RuntimeException( "exeeded max number of iterations="+ MAX_NUMBER_OF_ITERATIONS ); } return gammaOfA - sum * Math.exp( a*Math.log( x ) - x ); } static double MIN_DP = 1e-30; static double computeViaContinuedFraction( double a, double x ) { double b = x + 1 - a; double c = 1/MIN_DP; double d = 1/b; double h = d; for( int i=1; i<MAX_NUMBER_OF_ITERATIONS; i++ ) { double an = -i * (i-a); b += 2; d = an*d + b; c = an/c + b; if( Math.abs( c ) < MIN_DP ) c = MIN_DP; if( Math.abs( d ) < MIN_DP ) d = MIN_DP; d = 1 / d; double delta = c * d; h *= delta; if( Math.abs( delta - 1 ) < EPS ) return h * Math.exp( a * Math.log( x ) - x ); } throw new RuntimeException( "exeeded max number of iterations="+ MAX_NUMBER_OF_ITERATIONS ); } }