vnl_gamma.cxx
Go to the documentation of this file.
1 // This is core/vnl/vnl_gamma.cxx
2 #include <iostream>
3 #include <cassert>
4 #include "vnl_gamma.h"
5 //:
6 // \file
7 // \brief Complete and incomplete gamma function approximations
8 // \author Tim Cootes
9 
10 #if defined(__INTEL_COMPILER)
11 # pragma warning (disable:279) /* controlling expression is constant */
12 #endif
13 
14 //: Approximate gamma function
15 // Uses 6 parameter Lanczos approximation as described by Viktor Toth
16 // (http://www.rskey.org/gamma.htm)
17 // Accurate to about 3e-11.
18 double vnl_log_gamma(double x)
19 {
20  double zp = 2.50662827563479526904;
21  zp += 225.525584619175212544/x;
22  zp -= 268.295973841304927459/(x+1.0);
23  zp += 80.9030806934622512966/(x+2.0);
24  zp -= 5.00757863970517583837/(x+3.0);
25  zp += 0.0114684895434781459556/(x+4.0);
26 
27  double x1 = x+4.65;
28 
29  return std::log(zp)+(x-0.5)*std::log(x1)-x1;
30 }
31 
32 constexpr int MAX_ITS = 100;
33 const double MaxRelError = 3.0e-7;
34 const double vnl_very_small = 1.0e-30;
35 
36 //: Use series expansion of incomplete gamma function
37 static double vnl_gamma_series(double a, double x)
38 {
39  if (x>0)
40  {
41  double a_i=a;
42  double term_i=1.0/a;
43  double sum = term_i;
44  for (int i=1;i<=MAX_ITS;++i)
45  {
46  a_i+=1;
47  term_i *= x/a_i;
48  sum += term_i;
49  if (std::fabs(term_i) < std::fabs(sum)*MaxRelError)
50  return sum*std::exp(-x+a*std::log(x)-vnl_log_gamma(a));
51  }
52  std::cerr<<"vnl_gamma_series : Failed to converge in "<<MAX_ITS<<" steps\n"
53  <<"a = "<<a<<" x= "<< x <<"\nReturning best guess.\n";
54  return sum*std::exp(-x+a*std::log(x)-vnl_log_gamma(a));
55  }
56  else if (x < 0.0)
57  assert(!"vnl_gamma_series - x less than 0");
58 
59  return 0.0;
60 }
61 
62 //: Incomplete gamma using continued fraction representation
63 // Use Lentz's algorithm
64 // Continued fraction with terms a_i/b_i
65 // a_i = i*(a-i), b_i = (x+a-2i)
66 static double vnl_gamma_cont_frac(double a, double x)
67 {
68  double b_i=x+1.0-a;
69  double c=1.0/vnl_very_small;
70  double d=1.0/b_i;
71  double cf=d;
72  for (int i=1;i<=MAX_ITS;i++)
73  {
74  double a_i = i*(a-i);
75  b_i += 2.0;
76  d=a_i*d+b_i;
77  if (std::fabs(d) < vnl_very_small) d=vnl_very_small;
78  c=b_i+a_i/c;
79  if (std::fabs(c) < vnl_very_small) c=vnl_very_small;
80  d=1.0/d;
81  double delta=d*c;
82  cf *= delta;
83  if (std::fabs(delta-1.0) < MaxRelError)
84  return std::exp(-x+a*std::log(x)-vnl_log_gamma(a))*cf;
85  }
86 
87  std::cerr<<"vnl_gamma_cont_frac : Failed to converge in "<<MAX_ITS<<" steps\n"
88  <<"a = "<<a<<" x= "<<x<<std::endl;
89  return std::exp(-x+a*std::log(x)-vnl_log_gamma(a))*cf;
90 }
91 
92 double vnl_gamma_p(double a, double x)
93 {
94  if (x < 0.0 || a <= 0.0)
95  assert(!"vnl_gamma_p - Invalid arguments.");
96 
97  if (x < a+1.0)
98  return vnl_gamma_series(a,x); // Use series representation
99  else
100  return 1.0 - vnl_gamma_cont_frac(a,x); // Use continued fraction representation
101 }
102 
103 double vnl_gamma_q(double a, double x)
104 {
105  if (x < 0.0 || a <= 0.0)
106  assert(!"vnl_gamma_q - Invalid arguments.");
107 
108  if (x < a+1.0)
109  return 1.0-vnl_gamma_series(a,x); // Use series representation
110  else
111  return vnl_gamma_cont_frac(a,x); // Use continued fraction representation
112 }
113 
114 double vnl_digamma(double z)
115 {
116  double t0 = (z-0.5)/(z+4.65)-1.0;
117  double tlg = std::log(4.65+z);
118  double tc = 2.50662827563479526904;
119  double t1 = 225.525584619175212544/z;
120  double t2 = -268.295973841304927459/(1+z);
121  double t3 = +80.9030806934622512966/(2+z);
122  double t4 = -5.00757863970517583837/(3+z);
123  double t5 = 0.0114684895434781459556/(4+z);
124  double neu = t1/z + t2/(1+z) + t3/(2+z) + t4/(3+z) + t5/(4+z);
125  double den = tc + t1 + t2 + t3 + t4 + t5;
126  return t0 -(neu/den) + tlg;
127 }
double vnl_digamma(double z)
approximate digamma function, dLog[gamma[z]]/dz.
Definition: vnl_gamma.cxx:114
double vnl_gamma_q(double a, double x)
Normalised Incomplete gamma function, Q(a,x).
Definition: vnl_gamma.cxx:103
constexpr int MAX_ITS
Definition: vnl_gamma.cxx:32
const double MaxRelError
Definition: vnl_gamma.cxx:33
double vnl_log_gamma(double x)
Approximate gamma function.
Definition: vnl_gamma.cxx:18
Complete and incomplete gamma function approximations.
double vnl_gamma_p(double a, double x)
Normalised Incomplete gamma function, P(a,x).
Definition: vnl_gamma.cxx:92
const double vnl_very_small
Definition: vnl_gamma.cxx:34