00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2006, 2007, 2008, 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 This function is based on the CERNLIB routines GAUSS and 00084 DGAUSS which are documented at 00085 http://wwwasdoc.web.cern.ch/wwwasdoc/shortwrupsdir/d103/top.html 00086 00087 \future Allow user to change \c cst? 00088 */ 00089 template<class param_t, class func_t> class cern_gauss : 00090 public inte<param_t,func_t> { 00091 00092 public: 00093 00094 cern_gauss() { 00095 x[0]=0.96028985649753623; 00096 x[1]=0.79666647741362674; 00097 x[2]=0.52553240991632899; 00098 x[3]=0.18343464249564980; 00099 x[4]=0.98940093499164993; 00100 x[5]=0.94457502307323258; 00101 x[6]=0.86563120238783175; 00102 x[7]=0.75540440835500303; 00103 x[8]=0.61787624440264375; 00104 x[9]=0.45801677765722739; 00105 x[10]=0.28160355077925891; 00106 x[11]=0.95012509837637440e-1; 00107 00108 w[0]=0.10122853629037626; 00109 w[1]=0.22238103445337447; 00110 w[2]=0.31370664587788729; 00111 w[3]=0.36268378337836198; 00112 w[4]=0.27152459411754095e-1; 00113 w[5]=0.62253523938647893e-1; 00114 w[6]=0.95158511682492785e-1; 00115 w[7]=0.12462897125553387; 00116 w[8]=0.14959598881657673; 00117 w[9]=0.16915651939500254; 00118 w[10]=0.18260341504492359; 00119 w[11]=0.18945061045506850; 00120 } 00121 00122 /** \brief Integrate function \c func from \c a to \c b 00123 giving result \c res and error \c err 00124 */ 00125 virtual int integ_err(func_t &func, double a, double b, param_t &pa, 00126 double &res, double &err) { 00127 err_hnd->reset(); 00128 res=integ(func,a,b,pa); 00129 err=0.0; 00130 return err_hnd->get_errno(); 00131 } 00132 00133 /** 00134 \brief Integrate function \c func from \c a to \c b. 00135 */ 00136 virtual double integ(func_t &func, double a, double b, param_t &pa) { 00137 00138 double y1, y2; 00139 00140 int i; 00141 bool loop=true, loop2=false; 00142 static const double cst=0.005; 00143 double h=0.0; 00144 if (b==a) return 0.0; 00145 double cnst=cst/(b-a); 00146 double aa=0.0, bb=a; 00147 while (loop==true || loop2==true) { 00148 if (loop==true) { 00149 aa=bb; 00150 bb=b; 00151 } 00152 double c1=(bb+aa)/2.0; 00153 double c2=(bb-aa)/2.0; 00154 double s8=0.0; 00155 for(i=0;i<4;i++) { 00156 double u=c2*x[i]; 00157 func(c1+u,y1,pa); 00158 func(c1-u,y2,pa); 00159 s8+=w[i]*(y1+y2); 00160 } 00161 double s16=0.0; 00162 for(i=4;i<12;i++) { 00163 double u=c2*x[i]; 00164 func(c1+u,y1,pa); 00165 func(c1-u,y2,pa); 00166 s16+=w[i]*(y1+y2); 00167 } 00168 s16*=c2; 00169 00170 loop=false; 00171 loop2=false; 00172 if (fabs(s16-c2*s8)<this->tolf*(1.0+fabs(s16))) { 00173 h+=s16; 00174 if (bb!=b) loop=true; 00175 } else { 00176 bb=c1; 00177 if (1.0+cnst*fabs(c2)!=1.0) { 00178 loop2=true; 00179 } else { 00180 set_err 00181 ("Failed to reach required accuracy in cern_gauss::integ().", 00182 gsl_efailed); 00183 return 0.0; 00184 } 00185 } 00186 } 00187 return h; 00188 } 00189 00190 protected: 00191 00192 #ifndef DOXYGEN_INTERNAL 00193 00194 /** \name Integration constants 00195 */ 00196 //@{ 00197 double x[12], w[12]; 00198 //@} 00199 00200 #endif 00201 00202 }; 00203 00204 #ifndef DOXYGENP 00205 } 00206 #endif 00207 00208 #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