STK++ 0.9.13
STK_Funct_gamma.h
Go to the documentation of this file.
1/*--------------------------------------------------------------------*/
2/* Copyright (C) 2004-2016 Serge Iovleff, Université Lille 1, Inria
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) 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 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this program; if not, write to the
16 Free Software Foundation, Inc.,
17 59 Temple Place,
18 Suite 330,
19 Boston, MA 02111-1307
20 USA
21
22 Contact : S..._Dot_I..._At_stkpp_Dot_org (see copyright for ...)
23*/
24
25/*
26 * Project: Analysis
27 * Purpose: Declaration of functions around the gamma function
28 * Author: Serge Iovleff, S..._Dot_I..._At_stkpp_Dot_org (see copyright for ...)
29 **/
30
35#ifndef STK_FUNCT_GAMMA_H
36#define STK_FUNCT_GAMMA_H
37
38#include <vector>
39
40#include "STK_Const_Math.h"
41#include "STK_Const_Sequences.h"
42
43namespace STK
44{
45
46namespace Funct
47{
48// forward declaration
49Real factorial( int);
50Real lfactorial( int);
51
52Real factorial( Real const&);
53Real lfactorial( Real const&);
54
55Real gamma( Real const&);
56Real lgamma( Real const&);
57
58// raw versions
61
62Real factorial_raw( Real const&);
63Real lfactorial_raw( Real const&);
64
65Real gamma_raw( Real const&);
66Real lgamma_raw( Real const&);
67
73inline Real lanczosSerie(Real const& z)
74{
75 Real sum = 0.0;
76 for (int k=20; k>=0; k--)
77 sum += Const::lanczosCoefArray[k]/(z+k);
78 return 2.0240434640140357514731512432760e-10 + sum;
79}
80
86inline Real gammaLanczos(Real const& z)
87{
88 // 2 * sqrt(e/pi) = 1.86038273...
89 return 1.8603827342052657173362492472666631120594218414085774528900013
90 * exp((z-0.5)*(log(z+22.118910)-1.))
91 * lanczosSerie(z);
92}
93
98inline double stirlingSerie(Real const& z)
99{
100 const Real z2 = z * z;
101 return (z <= 50) ? ( Const::stirlingCoefArray[0]
102 + ( Const::stirlingCoefArray[1]
103 + ( Const::stirlingCoefArray[2]
104 + Const::stirlingCoefArray[3]/z2
105 )/z2
106 )/z2
107 )/z
108 : ( Const::stirlingCoefArray[0]
109 + ( Const::stirlingCoefArray[1]
110 + Const::stirlingCoefArray[2]/z2
111 )/z2
112 )/z
113 ;
114}
115
123inline Real gammaStirling( Real const& z)
124{ return Const::_SQRT2PI_ * exp((z-0.5)*(log(z)-1.)+stirlingSerie(z)-0.5);}
125
133inline Real lgammaStirling( Real const& z)
134{ return ( Const::_LNSQRT2PI_ + (z-0.5)*log(z) - z + stirlingSerie(z) );}
135
150{
151 int n = (int)std::floor(z);
152 // z is a discrete value
153 if (z == n)
154 { return (n<100) ? Const::lgammaStirlingErrorArray[n] : stirlingSerie(z);}
155 // z is a discrete value halves
156 if (z== n + 0.5)
157 { return (n<100) ? Const::lgammaStirlingErrorHalvesArray[n] : stirlingSerie(z);}
158 // other cases
159 return (z > 16) ? stirlingSerie(z) : lgamma(z) - (z-0.5)*log(z) + z - Const::_LNSQRT2PI_;
160}
161
176{ return (n<100.0) ? Const::lgammaStirlingErrorArray[n] : stirlingSerie(n);}
177
178
186inline Real factorial( int n)
187{
188 // Check if z is Available and finite
190 if (n < 0) { STKDOMAIN_ERROR_1ARG(factorial,n,"Negative argument");}
191 return factorial_raw(n);
192}
193inline Real factorial_raw( int n)
194{ return (n < 51) ? Const::factorialArray[n] : Funct::gamma_raw(n + 1.);}
195
204inline Real factorial( Real const& z)
205{
206 // Check if z is Available and finite
207 if (!Arithmetic<Real>::isFinite(z)) return z;
208 // Negative integers or reals arguments not allowed
209 if (z < 0 ||(z != std::floor(z))) { STKDOMAIN_ERROR_1ARG(factorial,z,"Negative or not discrete argument");}
210 return factorial_raw(z);
211}
212inline Real factorial_raw( Real const& z)
213{
214 const int n = std::floor(z);
215 return (n < 51) ? Const::factorialArray[n] : Funct::gamma_raw(z + 1.);
216}
217
225inline Real lfactorial(int n)
226{
227 // Check if z is Available and finite
228 if (!Arithmetic<int>::isFinite(n)) return n;
229 // Negative integers or reals arguments not allowed
230 if (n < 0) { STKDOMAIN_ERROR_1ARG(lfactorial,n,"Negative integer argument");}
231 // if n is a small number return a constant
232 return lfactorial_raw(n);
233}
234inline Real lfactorial_raw(int n)
235{ return (n < 51) ? Const::factorialLnArray[n] : lgamma( n + 1.);}
236
245inline Real lfactorial(Real const& z)
246{
247 // Check if z is Available and finite
248 if (!Arithmetic<Real>::isFinite(z)) return z;
249 // Negative integers or real arguments not allowed
250 if ((z < 0)||(z != std::floor(z)))
251 { STKDOMAIN_ERROR_1ARG(lfactorial,z,"Negative integer or decimal argument");}
252 // if n is a small number return a constant
253 return lfactorial_raw(z);
254}
255inline Real lfactorial_raw(Real const& z)
256{
257 const int n = (int)std::floor(z);
258 return (n < 51) ? Const::factorialLnArray[n] : lgamma(z + 1.);
259}
260
272inline Real gamma(Real const& z)
273{
274 // Check if z is Available and finite
275 if (!Arithmetic<Real>::isFinite(z)) return z;
276 // Negative integer argument not allowed
277 if ( z<=0 && z == std::floor(z))
278 { STKDOMAIN_ERROR_1ARG(Funct::gamma,z,"Negative integer or zero argument");}
279 return gamma_raw(z);
280}
281
282inline Real gamma_raw(Real const& z)
283{
284 int n = (int)std::floor(z);
285 // If z is an integer (z integer and z<0 is not possible)
286 if (z == n)
287 { return (z < 51) ? Const::factorialArray[(int)z-1] : gammaStirling(z);}
288 // compute the absolute value of x -> y and compute the sign of the gamma function
289 Real y = std::abs(z);
290 int ny = std::floor(y);
291 Real signgam = (z<0 && isEven(ny)) ? -1 : 1, value;
292 // if y is an integer and a half, use reflection formula
293 if (y == ny+0.5)
294 { value = (ny<50) ? Const::factorialHalvesArray[ny] : gammaStirling(y);}
295 else // normal case
296 {
297 if (y <= 8)
298 {
299 Real r = y-ny; // r in [0,1]
300 value = gammaLanczos(r); // use Lanzcos approximation
301 // scale result
302 for (int i=0; i<ny; i++) value *= (r+i);
303 }
304 else // shift value
305 {
306 if (y <=16)
307 {
308 value = gammaStirling(y+6.);
309 for (int i=5; i>=0; --i) value /= (y+i);
310 }
311 else
312 value = gammaStirling(y);
313 }
314 }
315 // z >0 terminate
316 if (z>0) return value;
317 // z <0 -> use reflection formula and check overflow
318 Real den = y*sin(Const::_PI_ *y)*value;
319 return (den == 0.0) ? signgam * Arithmetic<Real>::infinity() : -Const::_PI_/den;
320}
321
330inline Real lgamma(Real const& z)
331{
332 // Check if z is Available and finite
333 if (!Arithmetic<Real>::isFinite(z)) return z;
334 // Negative integer argument not allowed
335 if ( z<=0 && z == std::floor(z))
336 { STKDOMAIN_ERROR_1ARG(Funct::lgamma,z,"Negative integer or zero argument");}
337 return lgamma_raw(z);
338}
339inline Real lgamma_raw(Real const& z)
340{
341 // compute the absolute value of x -> y
342 Real y = std::abs(z), value;
343 int ny = std::floor(y);
344 // If x is an integer
345 if (y == ny)
346 { value = (ny<=50) ? Const::factorialLnArray[ny-1] : lgammaStirling(y);}
347 else
348 {
349 // If x is an integer and a half
350 if (y == ny+0.5)
351 { value = (ny<50) ? Const::factorialLnHalvesArray[ny] : lgammaStirling(y);}
352 else
353 {
354 // small values -> use gamma function
355 if (y <= 16) return log(std::abs(Funct::gamma_raw(z)));
356 else value = lgammaStirling(y);
357 }
358 }
359 // z >0 terminate
360 if (z>0) return value;
361 // z <0 -> use reflectiong formula
362 Real sinpiy = std::abs(sin(Const::_PI_ *y));
363 // overflow
364 return (sinpiy == 0.0) ? -Arithmetic<Real>::infinity()
365 : Const::_LNSQRTPI_2_+(z-0.5)*log(y)-z-log(sinpiy)+stirlingSerie(z);
366}
367
368} // namespace Funct
369
370} // namespace STK
371
372#endif // STK_FUNCT_GAMMA_H
In this file we give the main mathematical constants.
In this file we define static arrays with useful integer sequences .
#define STKDOMAIN_ERROR_1ARG(Where, Arg, Error)
Definition STK_Macros.h:165
The MultidimRegression class allows to regress a multidimensional output variable among a multivariat...
Real gammaStirling(Real const &z)
This function computes the gamma function using the Stirling approximation.
Real lanczosSerie(Real const &z)
Compute the Lanzcos correction series for the gamma function with n = 21 terms.
Real gammaLanczos(Real const &z)
Compute the gamma function using the Lanzcos expansion using n = 21 terms and r= 22....
const Real factorialArray[51]
array for the 51th fisrt factorial elements.
Real lgammaStirlingError(Real const &z)
Compute the error when we compute using the Stirling's formula.
Real gamma(Real const &)
This function computes the function .
Real lgammaStirling(Real const &z)
This function computes the log gamma function using the Stirling approximation.
Real factorial(int)
This function computes for integer argument.
Real lgamma(Real const &)
This function computes the function .
Real lfactorial(int)
This function computes for integer argument.
double stirlingSerie(Real const &z)
Compute the Stirling's series for the lgamma function.
Arrays::SumOp< Lhs, Rhs >::result_type sum(Lhs const &lhs, Rhs const &rhs)
convenience function for summing two arrays
bool isEven(int const &x)
is x an even number ?
Definition STK_Misc.h:83
double Real
STK fundamental type of Real values.
Real factorial_raw(int)
Real lfactorial_raw(int)
Real gamma_raw(Real const &)
Real lgamma_raw(Real const &)
The namespace STK is the main domain space of the Statistical ToolKit project.
Arithmetic properties of STK fundamental types.
static Type NA()
Adding a Non Available (NA) special number.