![]() |
Object-oriented Scientific Computing Library: Version 0.910
|
00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2006-2012, 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_DERIV_H 00024 #define O2SCL_CERN_DERIV_H 00025 00026 #include <o2scl/deriv.h> 00027 #include <o2scl/funct.h> 00028 #include <o2scl/string_conv.h> 00029 #include <o2scl/err_hnd.h> 00030 00031 #ifndef DOXYGENP 00032 namespace o2scl { 00033 #endif 00034 00035 /** \brief Numerical differentiation routine (CERNLIB) 00036 00037 This uses Romberg extrapolation to compute the 00038 derivative with the finite-differencing formula 00039 \f[ 00040 f^{\prime}(x) = [f(x+h)-f(x-h)]/(2h) 00041 \f] 00042 00043 If \ref deriv::verbose is greater than zero, then each iteration 00044 prints out the extrapolation table, and if \ref deriv::verbose 00045 is greater than 1, then a keypress is required at the end of 00046 each iteration. 00047 00048 For sufficiently difficult functions, the derivative computation 00049 can fail, and will call the error handler and return zero with 00050 zero error. 00051 00052 Based on the CERNLIB routine DERIV, which was 00053 based on \ref Rutishauser63 and is documented at 00054 http://wwwasdoc.web.cern.ch/wwwasdoc/shortwrupsdir/d401/top.html 00055 00056 An example demonstrating the usage of this class is 00057 given in <tt>examples/ex_deriv.cpp</tt> and the \ref ex_deriv_sect . 00058 00059 If \ref deriv::verbose is greater than zero, at each iteration 00060 this class prints something similar to 00061 \verbatim 00062 cern_deriv, iteration: 1 00063 (hh, a[k], derivative) list: 00064 -4.193459e-05 4.387643e-14 8.775286e-01 00065 -2.995402e-05 4.387792e-14 8.775585e-01 00066 -1.048405e-05 4.387845e-14 8.775690e-01 00067 -7.488654e-06 4.387882e-14 8.775765e-01 00068 -2.621038e-06 4.387895e-14 8.775791e-01 00069 -1.872173e-06 4.387905e-14 8.775810e-01 00070 -6.552611e-07 4.387908e-14 8.775817e-01 00071 -4.680438e-07 4.387910e-14 8.775821e-01 00072 -1.638153e-07 4.387911e-14 8.775823e-01 00073 \endverbatim 00074 If \ref deriv::verbose is greater than 1, a keypress is required 00075 after each iteration. 00076 00077 \note Second and third derivatives are computed by naive nested 00078 applications of the formula for the first derivative. 00079 No uncertainty for these derivatives is provided. 00080 00081 \future All of the coefficients appear to be fractions which 00082 could be replaced with exact representation? 00083 \future Record the number of function calls? 00084 00085 \comment 00086 - Maybe we should consider moving the table size to a template 00087 parameter? (1/29/07 - Probably not, as we'd have to re-derive 00088 the coefficients for sizes other than 10) 00089 \endcomment 00090 */ 00091 template<class func_t=funct> class cern_deriv : public deriv<func_t> { 00092 00093 public: 00094 00095 /// A scaling factor (default 1.0) 00096 double delta; 00097 00098 /// Extrapolation tolerance (default is \f$ 5 \times 10^{14} \f$) 00099 double eps; 00100 00101 cern_deriv() { 00102 dx[0]=0.0256; 00103 dx[1]=0.0192; 00104 dx[2]=0.0128; 00105 dx[3]=0.0096; 00106 dx[4]=0.0064; 00107 dx[5]=0.0048; 00108 dx[6]=0.0032; 00109 dx[7]=0.0024; 00110 dx[8]=0.0016; 00111 dx[9]=0.0012; 00112 00113 w[1][1]=1.3333333333333333; 00114 w[3][1]=1.0666666666666667; 00115 w[5][1]=1.0158730158730159; 00116 w[7][1]=1.0039215686274510; 00117 00118 w[2][1]=3.3333333333333333e-1; 00119 w[4][1]=6.6666666666666667e-2; 00120 w[6][1]=1.5873015873015873e-2; 00121 w[8][1]=3.9215686274509804e-3; 00122 00123 w[0][2]=2.2857142857142857; 00124 w[2][2]=1.1636363636363636; 00125 w[4][2]=1.0364372469635628; 00126 w[6][2]=1.0088669950738916; 00127 w[8][2]=1.0022021042329337; 00128 00129 w[1][2]=1.2857142857142857; 00130 w[3][2]=1.6363636363636364e-1; 00131 w[5][2]=3.6437246963562753e-2; 00132 w[7][2]=8.8669950738916256e-3; 00133 w[9][2]=2.2021042329336922e-3; 00134 00135 w[0][3]=1.8000000000000000; 00136 w[2][3]=1.1250000000000000; 00137 w[4][3]=1.0285714285714286; 00138 w[6][3]=1.0069930069930070; 00139 w[8][3]=1.0017391304347826; 00140 00141 w[1][3]=8.0000000000000000e-1; 00142 w[3][3]=1.2500000000000000e-1; 00143 w[5][3]=2.8571428571428571e-2; 00144 w[7][3]=6.9930069930069930e-3; 00145 w[9][3]=1.7391304347826087e-3; 00146 00147 delta=1.0; 00148 eps=5.0e-14; 00149 } 00150 00151 /** \brief Calculate the first derivative of \c func w.r.t. x and the 00152 uncertainty 00153 */ 00154 virtual int calc_err(double x, func_t &func, 00155 double &dfdx, double &err) { 00156 return calc_base<func_t>(x,func,dfdx,err); 00157 } 00158 00159 /// Return string denoting type ("cern_deriv") 00160 virtual const char *type() { return "cern_deriv"; } 00161 00162 protected: 00163 00164 #ifndef DOXYGEN_INTERNAL 00165 00166 /** \brief Internal template version of the derivative function 00167 */ 00168 template<class func2_t> int calc_base(double x, func2_t &func, 00169 double &dfdx, double &err) { 00170 00171 double t[10][10], a[10], del, hh; 00172 bool lev[10]={1,0,1,0,1,0,1,0,1,0}, lmt; 00173 int is, k, m; 00174 00175 del=10.0*fabs(delta); 00176 is=10; 00177 00178 do { 00179 is--; 00180 del=del/10.0; 00181 00182 if (is==0 || x+del*dx[9]==x) { 00183 delta=del; 00184 dfdx=0.0; 00185 err=0.0; 00186 std::string str="Calculation of derivative failed (is="+ 00187 itos(is)+" and del*dx[9]="+dtos(del*dx[9])+ 00188 ") in cern_deriv::calc_base()."; 00189 O2SCL_ERR_RET(str.c_str(),gsl_efailed); 00190 } 00191 00192 for(k=0;k<=9;k++) { 00193 hh=del*dx[k]; 00194 t[k][0]=(func(x+hh)-func(x-hh))/(hh+hh); 00195 a[k]=t[k][0]; 00196 } 00197 00198 if (a[0]>=a[9]) { 00199 for(k=0;k<=9;k++) a[k]=-a[k]; 00200 } 00201 00202 lmt=true; 00203 for(k=1;k<=9;k++) { 00204 hh=a[k-1]-a[k]; 00205 lmt=(lmt && (hh<=0.0 || fabs(hh)<=eps*fabs(a[k]))); 00206 } 00207 00208 if (this->verbose>0) { 00209 std::cout << "cern_deriv, iteration: " << 10-is << std::endl; 00210 std::cout << "(hh, a[k], derivative) list: " 00211 << std::endl; 00212 for(k=1;k<=9;k++) { 00213 std::cout << a[k-1]-a[k] << " " << eps*fabs(a[k]) << " " 00214 << t[k][0] << std::endl; 00215 } 00216 std::cout << "Converged: " << lmt << std::endl; 00217 if (this->verbose>1) { 00218 char ch; 00219 std::cin >> ch; 00220 } 00221 } 00222 00223 } while (lmt==false); 00224 00225 for(m=1;m<=9;m++) { 00226 for(k=0;k<=9-m;k++) { 00227 if (lev[m]) { 00228 t[k][m]=w[m-1][1]*t[k+1][m-1]-w[m][1]*t[k][m-1]; 00229 } else if (lev[k]) { 00230 t[k][m]=w[m-1][2]*t[k+1][m-1]-w[m][2]*t[k][m-1]; 00231 } else { 00232 t[k][m]=w[m-1][3]*t[k+1][m-1]-w[m][3]*t[k][m-1]; 00233 } 00234 } 00235 } 00236 dfdx=t[0][9]; 00237 if (dfdx!=0.0) err=(dfdx-t[0][8])/dfdx; 00238 else err=0.0; 00239 delta=del; 00240 00241 return 0; 00242 } 00243 00244 /** \brief Calculate the first derivative of \c func w.r.t. x 00245 00246 This is an internal version of calc() which is used in 00247 computing second and third derivatives 00248 */ 00249 virtual int calc_err_int(double x, funct &func, double &dfdx, 00250 double &err) { 00251 return calc_base<funct>(x,func,dfdx,err); 00252 } 00253 00254 /// \name Storage for the fixed coefficients 00255 //@{ 00256 double dx[10]; 00257 double w[10][4]; 00258 //@} 00259 00260 #endif 00261 00262 }; 00263 00264 #ifndef DOXYGENP 00265 } 00266 #endif 00267 00268 #endif 00269 00270
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).