Go to the documentation of this file.00001
00002 #include "vnl_gamma.h"
00003
00004
00005
00006
00007
00008 #include <vcl_iostream.h>
00009 #include <vcl_cassert.h>
00010
00011 #if defined(__INTEL_COMPILER)
00012 # pragma warning (disable:279)
00013 #endif
00014
00015
00016
00017
00018
00019 double vnl_log_gamma(double x)
00020 {
00021 double zp = 2.50662827563479526904;
00022 zp += 225.525584619175212544/x;
00023 zp -= 268.295973841304927459/(x+1.0);
00024 zp += 80.9030806934622512966/(x+2.0);
00025 zp -= 5.00757863970517583837/(x+3.0);
00026 zp += 0.0114684895434781459556/(x+4.0);
00027
00028 double x1 = x+4.65;
00029
00030 return vcl_log(zp)+(x-0.5)*vcl_log(x1)-x1;
00031 }
00032
00033 const int MAX_ITS = 100;
00034 const double MaxRelError = 3.0e-7;
00035 const double vnl_very_small = 1.0e-30;
00036
00037
00038 static double vnl_gamma_series(double a, double x)
00039 {
00040 if (x>0)
00041 {
00042 double a_i=a;
00043 double term_i=1.0/a;
00044 double sum = term_i;
00045 for (int i=1;i<=MAX_ITS;++i)
00046 {
00047 a_i+=1;
00048 term_i *= x/a_i;
00049 sum += term_i;
00050 if (vcl_fabs(term_i) < vcl_fabs(sum)*MaxRelError)
00051 return sum*vcl_exp(-x+a*vcl_log(x)-vnl_log_gamma(a));
00052 }
00053 vcl_cerr<<"vnl_gamma_series : Failed to converge in "<<MAX_ITS<<" steps\n"
00054 <<"a = "<<a<<" x= "<< x <<"\nReturning best guess.\n";
00055 return sum*vcl_exp(-x+a*vcl_log(x)-vnl_log_gamma(a));
00056 }
00057 else if (x < 0.0)
00058 assert(!"vnl_gamma_series - x less than 0");
00059
00060 return 0.0;
00061 }
00062
00063
00064
00065
00066
00067 static double vnl_gamma_cont_frac(double a, double x)
00068 {
00069 double b_i=x+1.0-a;
00070 double c=1.0/vnl_very_small;
00071 double d=1.0/b_i;
00072 double cf=d;
00073 for (int i=1;i<=MAX_ITS;i++)
00074 {
00075 double a_i = i*(a-i);
00076 b_i += 2.0;
00077 d=a_i*d+b_i;
00078 if (vcl_fabs(d) < vnl_very_small) d=vnl_very_small;
00079 c=b_i+a_i/c;
00080 if (vcl_fabs(c) < vnl_very_small) c=vnl_very_small;
00081 d=1.0/d;
00082 double delta=d*c;
00083 cf *= delta;
00084 if (vcl_fabs(delta-1.0) < MaxRelError)
00085 return vcl_exp(-x+a*vcl_log(x)-vnl_log_gamma(a))*cf;
00086 }
00087
00088 vcl_cerr<<"vnl_gamma_cont_frac : Failed to converge in "<<MAX_ITS<<" steps\n"
00089 <<"a = "<<a<<" x= "<<x<<vcl_endl;
00090 return vcl_exp(-x+a*vcl_log(x)-vnl_log_gamma(a))*cf;
00091 }
00092
00093 double vnl_gamma_p(double a, double x)
00094 {
00095 if (x < 0.0 || a <= 0.0)
00096 assert(!"vnl_gamma_p - Invalid arguments.");
00097
00098 if (x < a+1.0)
00099 return vnl_gamma_series(a,x);
00100 else
00101 return 1.0 - vnl_gamma_cont_frac(a,x);
00102 }
00103
00104 double vnl_gamma_q(double a, double x)
00105 {
00106 if (x < 0.0 || a <= 0.0)
00107 assert(!"vnl_gamma_q - Invalid arguments.");
00108
00109 if (x < a+1.0)
00110 return 1.0-vnl_gamma_series(a,x);
00111 else
00112 return vnl_gamma_cont_frac(a,x);
00113 }
00114
00115 double vnl_digamma(double z)
00116 {
00117 double t0 = (z-0.5)/(z+4.65)-1.0;
00118 double tlg = vcl_log(4.65+z);
00119 double tc = 2.50662827563479526904;
00120 double t1 = 225.525584619175212544/z;
00121 double t2 = -268.295973841304927459/(1+z);
00122 double t3 = +80.9030806934622512966/(2+z);
00123 double t4 = -5.00757863970517583837/(3+z);
00124 double t5 = 0.0114684895434781459556/(4+z);
00125 double neu = t1/z + t2/(1+z) + t3/(2+z) + t4/(3+z) + t5/(4+z);
00126 double den = tc + t1 + t2 + t3 + t4 + t5;
00127 return t0 -(neu/den) + tlg;
00128 }