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