00001 #ifdef CH_LANG_CC
00002
00003
00004
00005
00006
00007
00008
00009 #endif
00010
00011 #ifndef _ROOTSOLVER_H_
00012 #define _ROOTSOLVER_H_
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <cmath>
00023 #include <algorithm>
00024
00025 #include "CH_assert.H"
00026
00027 #include "BaseNamespaceHeader.H"
00028
00029 namespace RootSolver
00030 {
00031
00032 template <typename T> struct RootTr
00033 {
00034 };
00035
00036
00037 template <> struct RootTr<float>
00038 {
00039 enum
00040 {
00041 maxIter = 100
00042 };
00043
00044 static float eps()
00045 {
00046 return 3.0E-7;
00047 }
00048
00049 static float tolerance()
00050 {
00051 return 1.0e-6;
00052 }
00053 };
00054
00055
00056 template <> struct RootTr<double>
00057 {
00058 enum
00059 {
00060 maxIter = 100
00061 };
00062
00063 static double eps()
00064 {
00065 return 3.0E-15;
00066 }
00067
00068 static double tolerance()
00069 {
00070 return 1.0e-12;
00071 }
00072 };
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127 template <typename T, typename Func>
00128 T Brent(int& numIter,
00129 const Func& f,
00130 T aPt,
00131 T bPt,
00132 T tol = RootTr<T>::tolerance(),
00133 const unsigned MAXITER = RootTr<T>::maxIter)
00134 {
00135 CH_assert(tol >= 0.);
00136 CH_assert(MAXITER > 0);
00137 const T eps = RootTr<T>::eps();
00138 const int prec = (int)tol;
00139 if (((T)prec) == tol)
00140 {
00141 tol = std::pow(10., -std::abs(prec));
00142 }
00143 numIter = -1;
00144
00145
00146 unsigned i;
00147 T c, d, e;
00148 T p, q, r, s;
00149
00150 T fa = f(aPt);
00151 T fb = f(bPt);
00152
00153
00154 c = d = e = 0.0;
00155
00156 if (fb*fa > 0)
00157 {
00158 MayDay::Abort("RootSolver::Brent: Root must be bracketed");
00159 }
00160
00161 T fc = fb;
00162
00163 for (i = 0; i < MAXITER; i++)
00164 {
00165 if (fb*fc > 0)
00166 {
00167
00168 c = aPt;
00169 fc = fa;
00170 d = bPt - aPt;
00171 e = d;
00172 }
00173
00174 if (Abs(fc) < Abs(fb))
00175 {
00176 aPt = bPt;
00177 bPt = c;
00178 c = aPt;
00179 fa = fb;
00180 fb = fc;
00181 fc = fa;
00182 }
00183
00184
00185 const T tol1 = 2.0 * eps * Abs(bPt) + 0.5 * tol;
00186 const T xm = 0.5 * (c - bPt);
00187
00188 if (Abs(xm) <= tol1 || fb == 0.0)
00189 {
00190 break;
00191 }
00192
00193 if (Abs(e) >= tol1 && Abs(fa) > Abs(fb))
00194 {
00195
00196 s = fb / fa;
00197 if (aPt == c)
00198 {
00199 p = 2.0 * xm * s;
00200 q = 1.0 - s;
00201 }
00202 else
00203 {
00204 q = fa / fc;
00205 r = fb / fc;
00206 p = s * (2.0 * xm * q * (q-r) - (bPt-aPt) * (r-1.0));
00207 q = (q-1.0) * (r-1.0) * (s-1.0);
00208 }
00209
00210
00211 if (p > 0) q = -q;
00212
00213 p = Abs(p);
00214
00215 if (2.0 * p < std::min(((float)3.0)*xm*q-Abs(tol1*q),
00216 Abs(e*q)))
00217 {
00218
00219 e = d;
00220 d = p / q;
00221 }
00222 else
00223 {
00224
00225 d = xm;
00226 e = d;
00227 }
00228 }
00229 else
00230 {
00231
00232 d = xm;
00233 e = d;
00234 }
00235
00236
00237 aPt = bPt;
00238 fa = fb;
00239
00240
00241 if (Abs(d) > tol1)
00242 {
00243 bPt = bPt + d;
00244 }
00245 else
00246 {
00247 if (xm < 0) bPt = bPt - tol1;
00248 else bPt = bPt + tol1;
00249 }
00250
00251 fb = f(bPt);
00252 }
00253
00254 if (i >= MAXITER)
00255 {
00256 pout() << "RootSolver::Brent: exceeded maximum iterations: "
00257 << MAXITER << std::endl;
00258 }
00259
00260 numIter = i;
00261 return bPt;
00262 }
00263
00264 }
00265
00266 #include "BaseNamespaceFooter.H"
00267
00268 #endif