File: gamma.c

package info (click to toggle)
spd 1.3.0-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 3,572 kB
  • sloc: ansic: 25,938; fortran: 10,483; sh: 1,032; makefile: 75
file content (169 lines) | stat: -rw-r--r-- 4,914 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*
 *   Project: The SPD Image correction and azimuthal regrouping
 *                      http://forge.epn-campus.eu/projects/show/azimuthal
 *
 *   Copyright (C) 2005-2010 European Synchrotron Radiation Facility
 *                           Grenoble, France
 *
 *   Principal authors: P. Boesecke (boesecke@esrf.fr)
 *                      R. Wilcke (wilcke@esrf.fr)
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation, either version 3 of the License, or
 *   (at your option) 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 Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   and the GNU Lesser General Public License  along with this program.
 *   If not, see <http://www.gnu.org/licenses/>.
 */

/*+++
NAME

   gamma.c --- Gamma Function

SYNOPSIS

   double gamma( double X );

HISTORY
  2000-11-28 V1.0 Peter Boesecke
                  translated from PEARL function GAMMA PB 19-APR-1988
                  from COLLECTED ALGORITHMS FROM CACM 31-P 1- 0
                  ALGORITHM 31 (in ALGOL )
  2000-12-01 V1.01 calculation corrected
  2000-12-04 V1.02 -> gamma.c, .h
  2000-12-06 V1.03 Stirling's formula for x>20
---*/

/****************************************************************************
*  Include                                                                  *
****************************************************************************/

# include "gamma.h"
# define GAMMA_PI        3.1415926535897932384626

double _loggamma( double x ) 
{ // by Stirling's formula Knuth I: 111
  double invx, invx2, invx3, invx5, invx7;
  double sum=0.0;

  x -= 1.0;
  if (x <= 1.0) return( 1.0 );

  invx =  1.0 / x;
  invx2 = invx * invx;
  invx3 = invx2 * invx;
  invx5 = invx3 * invx2;
  invx7 = invx5 * invx2;

  sum = ((x + 0.5) * log(x)) - x;
  sum += log(2*GAMMA_PI) * 0.5;
  sum += (invx / 12.0) - (invx3 / 360.0);
  sum += (invx5 / 1260.0) - (invx7 / 1680.0);

  return ( sum );

} /* _loggamma */


/*+++------------------------------------------------------------------------
NAME
   gamma --- gamma function 

SYNOPSIS

   double gamma( double X );

DESCRIPTION

  For 2<=x<=3 gamma is approximated. In this interval the absolut
  error abs(eps(x))<0.25*1e-7. For x>3 gamma(x) is calculated 
  by iteration gamma(x) = (x-1) * (x-2) * ... * (x-n)*gamma(x-n),
  with 2<=(x-n)<=3. For x<2 gamma(x) = gamma(x+n) / ( x*(x+1)...(x+n-1) )
  again with 2<=(x-n)<=3. For x=0 or a negative integer gamma(x) is
  set to DBL_MAX.

RETURN VALUE
 
  gamma(x)

----------------------------------------------------------------------------*/
double gamma( double X ) 
{
  const double EPSMIN = 1e-30;
  const double EPS    = 1e-6;
  const double DUMVAL = DBL_MAX; 
  const double a0=.9999999758, a1=.4227874605, a2=.4117741955, a3=.0821117404;
  const double a4=.0721101567, a5=.0044511400, a6=.0051589951, a7=.0016063118;
  double GAMMA_WERT;
  double H,Y;

  H = 1.0; Y = X;

  while ( (fabs(Y-2.0)) >= EPS ) {
    if ( fabs(Y)<EPSMIN ) { H=DUMVAL; break; }
      else if (Y<2.0) { H = H/Y; Y=Y+1.0; }
      else if (Y>=20.0) { H = exp(_loggamma( Y )); break; }
      else if (Y>=3.0) { Y = Y-1.0;H=H*Y; } 
      else { Y=Y-2.0;
             H = (((((((a7*Y+a6)*Y+a5)*Y+a4)*Y+a3)*Y+a2)*Y+a1)*Y+a0)*H;
             break; }
    }
  GAMMA_WERT = H;

  return ( GAMMA_WERT );

} /* gamma */

/*+++------------------------------------------------------------------------
NAME
   loggamma --- natural logarithm of gamma function

SYNOPSIS

   double loggamma( double X );

DESCRIPTION

  Calculation of the natural logarithm of gamma for positive X.
  For X==0 or negative X DBL_MAX is returned.

RETURN VALUE

  loggamma(x)

----------------------------------------------------------------------------*/
double loggamma( double X )
{
  const double EPSMIN = 1e-30;
  const double EPS    = 1e-6;
  const double DUMVAL = DBL_MAX;
  const double a0=.9999999758, a1=.4227874605, a2=.4117741955, a3=.0821117404;
  const double a4=.0721101567, a5=.0044511400, a6=.0051589951, a7=.0016063118;
  double LOGGAMMA_WERT;
  double logH, Y;

  logH = 0.0; Y = X;

  while ( (fabs(Y-2.0)) >= EPS ) {
    if ( Y<EPSMIN ) { logH=DUMVAL; break; }
      else if (Y<2.0) { logH = logH-log(Y); Y=Y+1.0; }
      else if (Y>=20.0) { logH = _loggamma( Y ); break; }
      else if (Y>=3.0) { Y = Y-1.0;logH=logH+log(Y); }
      else { Y=Y-2.0;
             logH = logH + log(((((((a7*Y+a6)*Y+a5)*Y+a4)*Y+a3)*Y+a2)*Y+a1)*Y+a0);
             break; }
    }
  LOGGAMMA_WERT = logH;

  return ( LOGGAMMA_WERT );

} /* loggamma */