00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2006, 2007, 2008, 2009, Andrew W. Steiner 00005 00006 This file is part of O2scl. 00007 00008 O2scl is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 3 of the License, or 00011 (at your option) any later version. 00012 00013 O2scl is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with O2scl. If not, see <http://www.gnu.org/licenses/>. 00020 00021 ------------------------------------------------------------------- 00022 */ 00023 #ifndef O2SCL_CERN_GAUSS_H 00024 #define O2SCL_CERN_GAUSS_H 00025 00026 #include <o2scl/inte.h> 00027 00028 #ifndef DOXYGENP 00029 namespace o2scl { 00030 #endif 00031 00032 /** 00033 \brief Gaussian quadrature (CERNLIB) 00034 00035 For any interval \f$ (a,b) \f$, we define \f$ g_8(a,b) \f$ and 00036 \f$ g_{16}(a,b) \f$ to be the 8- and 16-point Gaussian 00037 quadrature approximations to 00038 \f[ 00039 I=\int_a^b f(x)~dx 00040 \f] 00041 and define 00042 \f[ 00043 r(a,b)=\frac{|g_{16}(a,b)-g_{8}(a,b)|}{1+g_{16}(a,b)} 00044 \f] 00045 The function integ() returns \f$ G \f$ given by 00046 \f[ 00047 G=\sum_{i=1}^{k} g_{16}(x_{i-1},x_i) 00048 \f] 00049 where \f$ x_0=a \f$ and \f$ x_k=b \f$ and the subdivision 00050 points \f$ x_i \f$ are given by 00051 \f[ 00052 x_i=x_{i-1}+\lambda(B-x_{i-1}) 00053 \f] 00054 where \f$ \lambda \f$ is the first number in the sequence \f$ 00055 1,\frac{1}{2},\frac{1}{4},... \f$ for which 00056 \f[ 00057 r(x_{i-1},x_i)<\mathrm{eps}. 00058 \f] 00059 If, at any stage, the ratio 00060 \f[ 00061 q=\left| \frac{x_i-x_{i-1}}{b-a} \right| 00062 \f] 00063 is so small so that \f$ 1+0.005 q \f$ is indistinguishable from 00064 unity, then the accuracy is required is not reachable and 00065 the error handler is called. 00066 00067 Unless there is severe cancellation, inte::tolf may be 00068 considered as specifying a bound on the relative error of the 00069 integral in the case that \f$ |I|>1 \f$ and an absolute error if 00070 \f$ |I|<1 \f$. More precisely, if \f$ k \f$ is the number of 00071 subintervals from above, and if 00072 \f[ 00073 I_{abs} = \int_a^b |f(x)|~dx 00074 \f] 00075 then 00076 \f[ 00077 \frac{|G-I|}{I_{abs}+k}<\mathrm{tolf} 00078 \f] 00079 will nearly always be true when no error is returned. For 00080 functions with no singualarities in the interval, the accuracy 00081 will usually be higher than this. 00082 00083 If the desired accuracy is not achieved, the integration 00084 functions will call the error handler and return the best guess, 00085 unless \ref inte::err_nonconv is false, in which case the error 00086 handler is not called. 00087 00088 This function is based on the CERNLIB routines GAUSS and 00089 DGAUSS which are documented at 00090 http://wwwasdoc.web.cern.ch/wwwasdoc/shortwrupsdir/d103/top.html 00091 00092 \future Allow user to change \c cst? 00093 */ 00094 template<class param_t, class func_t> class cern_gauss : 00095 public inte<param_t,func_t> { 00096 00097 public: 00098 00099 cern_gauss() { 00100 x[0]=0.96028985649753623; 00101 x[1]=0.79666647741362674; 00102 x[2]=0.52553240991632899; 00103 x[3]=0.18343464249564980; 00104 x[4]=0.98940093499164993; 00105 x[5]=0.94457502307323258; 00106 x[6]=0.86563120238783175; 00107 x[7]=0.75540440835500303; 00108 x[8]=0.61787624440264375; 00109 x[9]=0.45801677765722739; 00110 x[10]=0.28160355077925891; 00111 x[11]=0.95012509837637440e-1; 00112 00113 w[0]=0.10122853629037626; 00114 w[1]=0.22238103445337447; 00115 w[2]=0.31370664587788729; 00116 w[3]=0.36268378337836198; 00117 w[4]=0.27152459411754095e-1; 00118 w[5]=0.62253523938647893e-1; 00119 w[6]=0.95158511682492785e-1; 00120 w[7]=0.12462897125553387; 00121 w[8]=0.14959598881657673; 00122 w[9]=0.16915651939500254; 00123 w[10]=0.18260341504492359; 00124 w[11]=0.18945061045506850; 00125 } 00126 00127 /** \brief Integrate function \c func from \c a to \c b 00128 giving result \c res and error \c err 00129 */ 00130 virtual int integ_err(func_t &func, double a, double b, param_t &pa, 00131 double &res, double &err) { 00132 res=integ(func,a,b,pa); 00133 err=0.0; 00134 if (this->err_nonconv) return this->last_conv; 00135 return gsl_success; 00136 } 00137 00138 /** 00139 \brief Integrate function \c func from \c a to \c b. 00140 00141 \future Modify this to include iteration count information 00142 as done in \ref cern_cauchy 00143 */ 00144 virtual double integ(func_t &func, double a, double b, param_t &pa) { 00145 00146 double y1, y2; 00147 00148 this->last_conv=0; 00149 00150 int i; 00151 bool loop=true, loop2=false; 00152 static const double cst=0.005; 00153 double h=0.0; 00154 if (b==a) return 0.0; 00155 double cnst=cst/(b-a); 00156 double aa=0.0, bb=a; 00157 while (loop==true || loop2==true) { 00158 if (loop==true) { 00159 aa=bb; 00160 bb=b; 00161 } 00162 double c1=(bb+aa)/2.0; 00163 double c2=(bb-aa)/2.0; 00164 double s8=0.0; 00165 for(i=0;i<4;i++) { 00166 double u=c2*x[i]; 00167 func(c1+u,y1,pa); 00168 func(c1-u,y2,pa); 00169 s8+=w[i]*(y1+y2); 00170 } 00171 double s16=0.0; 00172 for(i=4;i<12;i++) { 00173 double u=c2*x[i]; 00174 func(c1+u,y1,pa); 00175 func(c1-u,y2,pa); 00176 s16+=w[i]*(y1+y2); 00177 } 00178 s16*=c2; 00179 00180 loop=false; 00181 loop2=false; 00182 if (fabs(s16-c2*s8)<this->tolf*(1.0+fabs(s16))) { 00183 h+=s16; 00184 if (bb!=b) loop=true; 00185 } else { 00186 bb=c1; 00187 if (1.0+cnst*fabs(c2)!=1.0) { 00188 loop2=true; 00189 } else { 00190 this->last_conv=gsl_efailed; 00191 O2SCL_CONV 00192 ("Failed to reach required accuracy in cern_gauss::integ().", 00193 gsl_efailed,this->err_nonconv); 00194 return h; 00195 } 00196 } 00197 } 00198 return h; 00199 } 00200 00201 protected: 00202 00203 #ifndef DOXYGEN_INTERNAL 00204 00205 /** \name Integration constants 00206 */ 00207 //@{ 00208 double x[12], w[12]; 00209 //@} 00210 00211 #endif 00212 00213 }; 00214 00215 #ifndef DOXYGENP 00216 } 00217 #endif 00218 00219 #endif
Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.
Project hosting provided by
,
O2scl Sourceforge Project Page