contrib/mul/mbl/mbl_gamma.cxx
Go to the documentation of this file.
00001 #include "mbl_gamma.h"
00002 #include <vcl_iostream.h>
00003 #include <vcl_cmath.h>
00004 #include <vcl_cstdlib.h> // vcl_abort()
00005 
00006 const int MAX_ITS = 200;
00007 const double EPS = 3.0e-7;
00008 const double FPMIN = 1.0e-30;
00009 
00010 double mbl_log_gamma(double xx)
00011 {
00012   double x,y,tmp,ser;
00013   static double cof[6]={76.18009172947146,-86.50532032941677,
00014                         24.01409824083091,-1.231739572450155,
00015                         0.1208650973866179e-2,-0.5395239384953e-5};
00016   int j;
00017 
00018   y=x=xx;
00019   tmp=x+5.5;
00020   tmp -= (x+0.5)*vcl_log(tmp);
00021   ser=1.000000000190015;
00022   for (j=0;j<=5;j++) ser += cof[j]/++y;
00023   return -tmp+vcl_log(2.5066282746310005*ser/x);
00024 }
00025 
00026 
00027 static double mbl_gamma_ser(double a, double x)
00028 {
00029   int n;
00030   double sum,del,ap,gln;
00031 
00032   gln=mbl_log_gamma(a);
00033   if (x>0)
00034   {
00035     ap=a;
00036     del=sum=1.0/a;
00037     for (n=1;n<=MAX_ITS;n++)
00038     {
00039       ++ap;
00040       del *= x/ap;
00041       sum += del;
00042       if (vcl_fabs(del) < vcl_fabs(sum)*EPS)
00043       {
00044         return sum*vcl_exp(-x+a*vcl_log(x)-(gln));
00045       }
00046     }
00047     vcl_cerr<<"mbl_gamma_ser : Failed to converge."<<vcl_endl;
00048     vcl_cerr<<"a = "<<a<<"   x= "<<x<<vcl_endl;
00049     vcl_cerr<<"Returning best guess."<<vcl_endl;
00050     // vcl_abort();
00051   }
00052   else
00053   {
00054     if (x < 0.0)
00055     {
00056       vcl_cerr<<"mbl_gamma_ser : x less than 0"<<vcl_endl;
00057       vcl_abort();
00058     }
00059   }
00060 
00061   return 0.0;
00062 }
00063 
00064 
00065 static double NR_log_gamma_cf(double a, double x)
00066 {
00067   int i;
00068   double an,b,c,d,del,h,gln;
00069 
00070   gln=mbl_log_gamma(a);
00071   b=x+1.0-a;
00072   c=1.0/FPMIN;
00073   d=1.0/b;
00074   h=d;
00075   for (i=1;i<=MAX_ITS;i++)
00076   {
00077     an = -i*(i-a);
00078     b += 2.0;
00079     d=an*d+b;
00080     if (vcl_fabs(d) < FPMIN) d=FPMIN;
00081     c=b+an/c;
00082     if (vcl_fabs(c) < FPMIN) c=FPMIN;
00083     d=1.0/d;
00084     del=d*c;
00085     h *= del;
00086     if (vcl_fabs(del-1.0) < EPS) break;
00087   }
00088   if (i > MAX_ITS)
00089   {
00090     vcl_cerr<<"NR_log_gamma_cf : Failed to converge."<<vcl_endl;
00091     vcl_abort();
00092   }
00093   return -x+a*vcl_log(x)-(gln)+vcl_log(h);
00094 }
00095 
00096 static double mbl_gamma_cf(double a, double x)
00097 {
00098   int i;
00099   double an,b,c,d,del,h,gln;
00100 
00101   gln=mbl_log_gamma(a);
00102   b=x+1.0-a;
00103   c=1.0/FPMIN;
00104   d=1.0/b;
00105   h=d;
00106   for (i=1;i<=MAX_ITS;i++)
00107   {
00108     an = -i*(i-a);
00109     b += 2.0;
00110     d=an*d+b;
00111     if (vcl_fabs(d) < FPMIN) d=FPMIN;
00112     c=b+an/c;
00113     if (vcl_fabs(c) < FPMIN) c=FPMIN;
00114     d=1.0/d;
00115     del=d*c;
00116     h *= del;
00117     if (vcl_fabs(del-1.0) < EPS) break;
00118   }
00119   if (i > MAX_ITS)
00120   {
00121     vcl_cerr<<"mbl_gamma_cf : Failed to converge. a="<<a<<" x="<<x<<vcl_endl;
00122     return 1.0; // Arbitrary
00123   }
00124   return vcl_exp(-x+a*vcl_log(x)-(gln))*h;
00125 }
00126 
00127 double mbl_gamma_p(double a, double x)
00128 {
00129 #ifndef NDEBUG
00130   if ((x < 0.0) || (a <= 0.0))
00131   {
00132     vcl_cerr<<"mbl_gamma_p : Invalid arguments."<<vcl_endl;
00133     vcl_abort();
00134   }
00135 #endif
00136 
00137   if (x < (a+1.0))
00138   {
00139     return mbl_gamma_ser(a,x); // Use series representation
00140   }
00141   else
00142   {
00143     return 1 - mbl_gamma_cf(a,x); // Use continued fraction representation
00144   }
00145 }
00146 
00147 double mbl_gamma_q(double a, double x)
00148 {
00149 #ifndef NDEBUG
00150   if ((x < 0.0) || (a <= 0.0))
00151   {
00152     vcl_cerr<<"mbl_gamma_q : Invalid arguments."<<vcl_endl;
00153     vcl_abort();
00154   }
00155 #endif
00156 
00157   if (x < (a+1.0))
00158   {
00159     return 1.0-mbl_gamma_ser(a,x); // Use series representation
00160   }
00161   else
00162   {
00163     return mbl_gamma_cf(a,x); // Use continued fraction representation
00164   }
00165 }
00166 
00167 double mbl_log_gamma_q(double a, double x)
00168 {
00169 #ifndef NDEBUG
00170   if ((x < 0.0) || (a <= 0.0))
00171   {
00172     vcl_cerr<<"mbl_log_gamma_q : Invalid arguments."<<vcl_endl;
00173     vcl_abort();
00174   }
00175 #endif
00176 
00177   if (x < (a+1.0))
00178   {
00179     return vcl_log(1.0 - mbl_gamma_ser(a,x)); // Use series representation
00180   }
00181   else
00182   {
00183     return NR_log_gamma_cf(a,x); // Use continued fraction representation
00184   }
00185 }