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
00023 #include <cmath>
00024 #include <algorithm>
00025
00026 #include "CH_assert.H"
00027
00028 #include "BaseNamespaceHeader.H"
00029
00030 namespace RootSolver
00031 {
00032
00033 template <typename T> struct RootTr
00034 {
00035 };
00036
00037
00038 template <> struct RootTr<float>
00039 {
00040 enum
00041 {
00042 maxIter = 100
00043 };
00044
00045 static float eps()
00046 {
00047 return 3.0E-7;
00048 }
00049
00050 static float tolerance()
00051 {
00052 return 1.0e-6;
00053 }
00054 };
00055
00056
00057 template <> struct RootTr<double>
00058 {
00059 enum
00060 {
00061 maxIter = 100
00062 };
00063
00064 static double eps()
00065 {
00066 return 3.0E-15;
00067 }
00068
00069 static double tolerance()
00070 {
00071 return 1.0e-12;
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
00128 template <typename T, typename Func>
00129 T Brent(int& numIter,
00130 const Func& f,
00131 T aPt,
00132 T bPt,
00133 T tol = RootTr<T>::tolerance(),
00134 const unsigned MAXITER = RootTr<T>::maxIter)
00135 {
00136 CH_assert(tol >= 0.);
00137 CH_assert(MAXITER > 0);
00138 const T eps = RootTr<T>::eps();
00139 const int prec = (int)tol;
00140 if (((T)prec) == tol)
00141 {
00142 tol = std::pow(10., -std::abs(prec));
00143 }
00144 numIter = -1;
00145
00146
00147 unsigned i;
00148 T c, d, e;
00149 T p, q, r, s;
00150
00151 T fa = f(aPt);
00152 T fb = f(bPt);
00153
00154
00155 c = d = e = 0.0;
00156
00157 if (fb*fa > 0)
00158 {
00159 MayDay::Abort("RootSolver::Brent: Root must be bracketed");
00160 }
00161
00162 T fc = fb;
00163
00164 for (i = 0; i < MAXITER; i++)
00165 {
00166 if (fb*fc > 0)
00167 {
00168
00169 c = aPt;
00170 fc = fa;
00171 d = bPt - aPt;
00172 e = d;
00173 }
00174
00175 if (std::fabs(fc) < std::fabs(fb))
00176 {
00177 aPt = bPt;
00178 bPt = c;
00179 c = aPt;
00180 fa = fb;
00181 fb = fc;
00182 fc = fa;
00183 }
00184
00185
00186 const T tol1 = 2.0 * eps * std::fabs(bPt) + 0.5 * tol;
00187 const T xm = 0.5 * (c - bPt);
00188
00189 if (std::fabs(xm) <= tol1 || fb == 0.0)
00190 {
00191 break;
00192 }
00193
00194 if (std::fabs(e) >= tol1 && std::fabs(fa) > std::fabs(fb))
00195 {
00196
00197 s = fb / fa;
00198 if (aPt == c)
00199 {
00200 p = 2.0 * xm * s;
00201 q = 1.0 - s;
00202 }
00203 else
00204 {
00205 q = fa / fc;
00206 r = fb / fc;
00207 p = s * (2.0 * xm * q * (q-r) - (bPt-aPt) * (r-1.0));
00208 q = (q-1.0) * (r-1.0) * (s-1.0);
00209 }
00210
00211
00212 if (p > 0) q = -q;
00213
00214 p = std::fabs(p);
00215
00216 if (2.0 * p < std::min(((float)3.0)*xm*q-std::fabs(tol1*q),
00217 std::fabs(e*q)))
00218 {
00219
00220 e = d;
00221 d = p / q;
00222 }
00223 else
00224 {
00225
00226 d = xm;
00227 e = d;
00228 }
00229 }
00230 else
00231 {
00232
00233 d = xm;
00234 e = d;
00235 }
00236
00237
00238 aPt = bPt;
00239 fa = fb;
00240
00241
00242 if (std::fabs(d) > tol1)
00243 {
00244 bPt = bPt + d;
00245 }
00246 else
00247 {
00248 if (xm < 0) bPt = bPt - tol1;
00249 else bPt = bPt + tol1;
00250 }
00251
00252 fb = f(bPt);
00253 }
00254
00255 if (i >= MAXITER)
00256 {
00257 std::cerr << "RootSolver::Brent: exceeded maximum iterations: "
00258 << MAXITER << std::endl;
00259 }
00260
00261 numIter = i;
00262 return bPt;
00263 }
00264
00265 }
00266
00267 #include "BaseNamespaceFooter.H"
00268
00269 #endif