00001 // 00002 // ******************************************************************** 00003 // * License and Disclaimer * 00004 // * * 00005 // * The Geant4 software is copyright of the Copyright Holders of * 00006 // * the Geant4 Collaboration. It is provided under the terms and * 00007 // * conditions of the Geant4 Software License, included in the file * 00008 // * LICENSE and available at http://cern.ch/geant4/license . These * 00009 // * include a list of copyright holders. * 00010 // * * 00011 // * Neither the authors of this software system, nor their employing * 00012 // * institutes,nor the agencies providing financial support for this * 00013 // * work make any representation or warranty, express or implied, * 00014 // * regarding this software system or assume any liability for its * 00015 // * use. Please see the license in the file LICENSE and URL above * 00016 // * for the full disclaimer and the limitation of liability. * 00017 // * * 00018 // * This code implementation is the result of the scientific and * 00019 // * technical work of the GEANT4 collaboration. * 00020 // * By using, copying, modifying or distributing the software (or * 00021 // * any work based on the software) you agree to acknowledge its * 00022 // * use in resulting scientific publications, and indicate your * 00023 // * acceptance of all terms of the Geant4 Software license. * 00024 // ******************************************************************** 00025 // 00026 // $Id: Gamma.cc 69796 2013-05-15 13:26:12Z gcosmo $ 00027 // 00028 // 00029 // ------------------------------------------------------------ 00030 // GEANT 4 class implementation 00031 // ------------------------------------------------------------ 00032 00033 #include <cmath> 00034 #include <string.h> 00035 #include "Gamma.hh" 00036 00037 MyGamma::MyGamma(){} 00038 00039 MyGamma::~MyGamma(){} 00040 00041 //____________________________________________________________________________ 00042 double MyGamma::Gamma(double z) 00043 { 00044 // Computation of gamma(z) for all z>0. 00045 // 00046 // The algorithm is based on the article by C.Lanczos [1] as denoted in 00047 // Numerical Recipes 2nd ed. on p. 207 (W.H.Press et al.). 00048 // 00049 // [1] C.Lanczos, SIAM Journal of Numerical Analysis B1 (1964), 86. 00050 // 00051 //--- Nve 14-nov-1998 UU-SAP Utrecht 00052 00053 if (z<=0) return 0; 00054 00055 double v = LnGamma(z); 00056 return std::exp(v); 00057 } 00058 00059 //____________________________________________________________________________ 00060 double MyGamma::Gamma(double a,double x) 00061 { 00062 // Computation of the incomplete gamma function P(a,x) 00063 // 00064 // The algorithm is based on the formulas and code as denoted in 00065 // Numerical Recipes 2nd ed. on p. 210-212 (W.H.Press et al.). 00066 // 00067 //--- Nve 14-nov-1998 UU-SAP Utrecht 00068 00069 if (a <= 0 || x <= 0) return 0; 00070 00071 if (x < (a+1)) return GamSer(a,x); 00072 else return GamCf(a,x); 00073 } 00074 00075 //____________________________________________________________________________ 00076 double MyGamma::GamCf(double a,double x) 00077 { 00078 // Computation of the incomplete gamma function P(a,x) 00079 // via its continued fraction representation. 00080 // 00081 // The algorithm is based on the formulas and code as denoted in 00082 // Numerical Recipes 2nd ed. on p. 210-212 (W.H.Press et al.). 00083 // 00084 //--- Nve 14-nov-1998 UU-SAP Utrecht 00085 00086 int itmax = 100; // Maximum number of iterations 00087 double eps = 3.e-7; // Relative accuracy 00088 double fpmin = 1.e-30; // Smallest double value allowed here 00089 00090 if (a <= 0 || x <= 0) return 0; 00091 00092 double gln = LnGamma(a); 00093 double b = x+1-a; 00094 double c = 1/fpmin; 00095 double d = 1/b; 00096 double h = d; 00097 double an,del; 00098 for (int i=1; i<=itmax; i++) { 00099 an = double(-i)*(double(i)-a); 00100 b += 2; 00101 d = an*d+b; 00102 if (Abs(d) < fpmin) d = fpmin; 00103 c = b+an/c; 00104 if (Abs(c) < fpmin) c = fpmin; 00105 d = 1/d; 00106 del = d*c; 00107 h = h*del; 00108 if (Abs(del-1) < eps) break; 00109 //if (i==itmax) cout << "*GamCf(a,x)* a too large or itmax too small" << endl; 00110 } 00111 double v = Exp(-x+a*Log(x)-gln)*h; 00112 return (1-v); 00113 } 00114 00115 //____________________________________________________________________________ 00116 double MyGamma::GamSer(double a,double x) 00117 { 00118 // Computation of the incomplete gamma function P(a,x) 00119 // via its series representation. 00120 // 00121 // The algorithm is based on the formulas and code as denoted in 00122 // Numerical Recipes 2nd ed. on p. 210-212 (W.H.Press et al.). 00123 // 00124 //--- Nve 14-nov-1998 UU-SAP Utrecht 00125 00126 int itmax = 100; // Maximum number of iterations 00127 double eps = 3.e-7; // Relative accuracy 00128 00129 if (a <= 0 || x <= 0) return 0; 00130 00131 double gln = LnGamma(a); 00132 double ap = a; 00133 double sum = 1/a; 00134 double del = sum; 00135 for (int n=1; n<=itmax; n++) { 00136 ap += 1; 00137 del = del*x/ap; 00138 sum += del; 00139 if (MyGamma::Abs(del) < Abs(sum*eps)) break; 00140 //if (n==itmax) cout << "*GamSer(a,x)* a too large or itmax too small" << endl; 00141 } 00142 double v = sum*Exp(-x+a*Log(x)-gln); 00143 return v; 00144 } 00145 00146 00147 double MyGamma::LnGamma(double z) 00148 { 00149 // Computation of ln[gamma(z)] for all z>0. 00150 // 00151 // The algorithm is based on the article by C.Lanczos [1] as denoted in 00152 // Numerical Recipes 2nd ed. on p. 207 (W.H.Press et al.). 00153 // 00154 // [1] C.Lanczos, SIAM Journal of Numerical Analysis B1 (1964), 86. 00155 // 00156 // The accuracy of the result is better than 2e-10. 00157 // 00158 //--- Nve 14-nov-1998 UU-SAP Utrecht 00159 00160 if (z<=0) return 0; 00161 00162 // Coefficients for the series expansion 00163 double c[7] = { 2.5066282746310005, 76.18009172947146, -86.50532032941677 00164 ,24.01409824083091, -1.231739572450155, 0.1208650973866179e-2 00165 ,-0.5395239384953e-5}; 00166 00167 double x = z; 00168 double y = x; 00169 double tmp = x+5.5; 00170 tmp = (x+0.5)*Log(tmp)-tmp; 00171 double ser = 1.000000000190015; 00172 for (int i=1; i<7; i++) { 00173 y += 1; 00174 ser += c[i]/y; 00175 } 00176 double v = tmp+Log(c[0]*ser/x); 00177 return v; 00178 }