Files
geant4/source/processes/hadronic/models/lend/src/nf_incompleteGammaFunctions.cc
T
2016-06-10 14:11:04 +02:00

191 lines
4.9 KiB
C++

/* igam.c
*
* Incomplete gamma integral
*
*
* DESCRIPTION:
*
* The function is defined by
*
* x
* -
* | | -t a-1
* igam(a,x) = | e t dt.
* | |
* -
* 0
*
*
* In this implementation both arguments must be positive.
* The integral is evaluated by either a power series or
* continued fraction expansion, depending on the relative
* values of a and x.
*
* ACCURACY:
*
* Relative error:
* arithmetic domain # trials peak rms
* IEEE 0,30 200000 3.6e-14 2.9e-15
* IEEE 0,100 300000 9.9e-14 1.5e-14
*/
/* igamc()
*
* Complemented incomplete gamma integral
*
*
* DESCRIPTION:
*
* The function is defined by
*
*
* igamc(a,x) = 1 - igam(a,x)
*
* inf.
* -
* | | -t a-1
* = | e t dt.
* | |
* -
* x
*
*
* In this implementation both arguments must be positive.
* The integral is evaluated by either a power series or
* continued fraction expansion, depending on the relative
* values of a and x.
*
* ACCURACY:
*
* Tested at random a, x.
* a x Relative error:
* arithmetic domain domain # trials peak rms
* IEEE 0.5,100 0,100 200000 1.9e-14 1.7e-15
* IEEE 0.01,0.5 0,100 200000 1.4e-13 1.6e-15
*/
/*
Cephes Math Library Release 2.8: June, 2000
Copyright 1985, 1987, 2000 by Stephen L. Moshier
*/
#include "nf_specialFunctions.h"
#if defined __cplusplus
#include <cmath>
#include "G4Exp.hh"
#include "G4Log.hh"
namespace GIDI {
using namespace GIDI;
using namespace std;
#endif
static double big = 4.503599627370496e15;
static double biginv = 2.22044604925031308085e-16;
/*
************************************************************
*/
double nf_incompleteGammaFunctionComplementary( double a, double x, nfu_status *status ) {
double ans, ax, c, yc, r, t, y, z;
double pk, pkm1, pkm2, qk, qkm1, qkm2;
*status = nfu_badInput;
if( !isfinite( x ) ) return( x );
*status = nfu_Okay;
if( ( x <= 0 ) || ( a <= 0 ) ) return( 1.0 );
if( ( x < 1.0 ) || ( x < a ) ) return( nf_gammaFunction( a, status ) - nf_incompleteGammaFunction( a, x, status ) );
ax = G4Exp( a * G4Log( x ) - x );
if( ax == 0. ) return( 0.0 );
if( x < 10000. ) {
y = 1.0 - a; /* continued fraction */
z = x + y + 1.0;
c = 0.0;
pkm2 = 1.0;
qkm2 = x;
pkm1 = x + 1.0;
qkm1 = z * x;
ans = pkm1 / qkm1;
do {
c += 1.0;
y += 1.0;
z += 2.0;
yc = y * c;
pk = pkm1 * z - pkm2 * yc;
qk = qkm1 * z - qkm2 * yc;
if( qk != 0 ) {
r = pk / qk;
t = fabs( ( ans - r ) / r );
ans = r; }
else {
t = 1.0;
}
pkm2 = pkm1;
pkm1 = pk;
qkm2 = qkm1;
qkm1 = qk;
if( fabs( pk ) > big ) {
pkm2 *= biginv;
pkm1 *= biginv;
qkm2 *= biginv;
qkm1 *= biginv;
}
} while( t > DBL_EPSILON ); } // Loop checking, 11.06.2015, T. Koi
else { /* Asymptotic expansion. */
y = 1. / x;
r = a;
c = 1.;
ans = 1.;
do {
a -= 1.;
c *= a * y;
ans += c;
} while( fabs( c ) > 100 * ans * DBL_EPSILON ); // Loop checking, 11.06.2015, T. Koi
}
return( ans * ax );
}
/*
************************************************************
*/
double nf_incompleteGammaFunction( double a, double x, nfu_status *status ) {
/* left tail of incomplete gamma function:
*
* inf. k
* a -x - x
* x e > ----------
* - -
* k=0 | (a+k+1)
*/
double ans, ax, c, r;
*status = nfu_badInput;
if( !isfinite( x ) ) return( x );
*status = nfu_Okay;
if( ( x <= 0 ) || ( a <= 0 ) ) return( 0.0 );
if( ( x > 1.0 ) && ( x > a ) ) return( nf_gammaFunction( a, status ) - nf_incompleteGammaFunctionComplementary( a, x, status ) );
ax = G4Exp( a * G4Log( x ) - x ); /* Compute x**a * exp(-x) */
if( ax == 0. ) return( 0.0 );
r = a; /* power series */
c = 1.0;
ans = 1.0;
do {
r += 1.0;
c *= x / r;
ans += c;
} while( c > ans * DBL_EPSILON ); // Loop checking, 11.06.2015, T. Koi
return( ans * ax / a );
}
#if defined __cplusplus
}
#endif