annotate DEPENDENCIES/generic/include/boost/math/tools/toms748_solve.hpp @ 125:34e428693f5d vext

Vext -> Repoint
author Chris Cannam
date Thu, 14 Jun 2018 11:15:39 +0100
parents c530137014c0
children
rev   line source
Chris@16 1 // (C) Copyright John Maddock 2006.
Chris@16 2 // Use, modification and distribution are subject to the
Chris@16 3 // Boost Software License, Version 1.0. (See accompanying file
Chris@16 4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Chris@16 5
Chris@16 6 #ifndef BOOST_MATH_TOOLS_SOLVE_ROOT_HPP
Chris@16 7 #define BOOST_MATH_TOOLS_SOLVE_ROOT_HPP
Chris@16 8
Chris@16 9 #ifdef _MSC_VER
Chris@16 10 #pragma once
Chris@16 11 #endif
Chris@16 12
Chris@16 13 #include <boost/math/tools/precision.hpp>
Chris@16 14 #include <boost/math/policies/error_handling.hpp>
Chris@16 15 #include <boost/math/tools/config.hpp>
Chris@16 16 #include <boost/math/special_functions/sign.hpp>
Chris@16 17 #include <boost/cstdint.hpp>
Chris@16 18 #include <limits>
Chris@16 19
Chris@101 20 #ifdef BOOST_MATH_LOG_ROOT_ITERATIONS
Chris@101 21 # define BOOST_MATH_LOGGER_INCLUDE <boost/math/tools/iteration_logger.hpp>
Chris@101 22 # include BOOST_MATH_LOGGER_INCLUDE
Chris@101 23 # undef BOOST_MATH_LOGGER_INCLUDE
Chris@101 24 #else
Chris@101 25 # define BOOST_MATH_LOG_COUNT(count)
Chris@101 26 #endif
Chris@101 27
Chris@16 28 namespace boost{ namespace math{ namespace tools{
Chris@16 29
Chris@16 30 template <class T>
Chris@16 31 class eps_tolerance
Chris@16 32 {
Chris@16 33 public:
Chris@16 34 eps_tolerance(unsigned bits)
Chris@16 35 {
Chris@16 36 BOOST_MATH_STD_USING
Chris@16 37 eps = (std::max)(T(ldexp(1.0F, 1-bits)), T(4 * tools::epsilon<T>()));
Chris@16 38 }
Chris@16 39 bool operator()(const T& a, const T& b)
Chris@16 40 {
Chris@16 41 BOOST_MATH_STD_USING
Chris@16 42 return fabs(a - b) <= (eps * (std::min)(fabs(a), fabs(b)));
Chris@16 43 }
Chris@16 44 private:
Chris@16 45 T eps;
Chris@16 46 };
Chris@16 47
Chris@16 48 struct equal_floor
Chris@16 49 {
Chris@16 50 equal_floor(){}
Chris@16 51 template <class T>
Chris@16 52 bool operator()(const T& a, const T& b)
Chris@16 53 {
Chris@16 54 BOOST_MATH_STD_USING
Chris@16 55 return floor(a) == floor(b);
Chris@16 56 }
Chris@16 57 };
Chris@16 58
Chris@16 59 struct equal_ceil
Chris@16 60 {
Chris@16 61 equal_ceil(){}
Chris@16 62 template <class T>
Chris@16 63 bool operator()(const T& a, const T& b)
Chris@16 64 {
Chris@16 65 BOOST_MATH_STD_USING
Chris@16 66 return ceil(a) == ceil(b);
Chris@16 67 }
Chris@16 68 };
Chris@16 69
Chris@16 70 struct equal_nearest_integer
Chris@16 71 {
Chris@16 72 equal_nearest_integer(){}
Chris@16 73 template <class T>
Chris@16 74 bool operator()(const T& a, const T& b)
Chris@16 75 {
Chris@16 76 BOOST_MATH_STD_USING
Chris@16 77 return floor(a + 0.5f) == floor(b + 0.5f);
Chris@16 78 }
Chris@16 79 };
Chris@16 80
Chris@16 81 namespace detail{
Chris@16 82
Chris@16 83 template <class F, class T>
Chris@16 84 void bracket(F f, T& a, T& b, T c, T& fa, T& fb, T& d, T& fd)
Chris@16 85 {
Chris@16 86 //
Chris@16 87 // Given a point c inside the existing enclosing interval
Chris@16 88 // [a, b] sets a = c if f(c) == 0, otherwise finds the new
Chris@16 89 // enclosing interval: either [a, c] or [c, b] and sets
Chris@16 90 // d and fd to the point that has just been removed from
Chris@16 91 // the interval. In other words d is the third best guess
Chris@16 92 // to the root.
Chris@16 93 //
Chris@16 94 BOOST_MATH_STD_USING // For ADL of std math functions
Chris@16 95 T tol = tools::epsilon<T>() * 2;
Chris@16 96 //
Chris@16 97 // If the interval [a,b] is very small, or if c is too close
Chris@16 98 // to one end of the interval then we need to adjust the
Chris@16 99 // location of c accordingly:
Chris@16 100 //
Chris@16 101 if((b - a) < 2 * tol * a)
Chris@16 102 {
Chris@16 103 c = a + (b - a) / 2;
Chris@16 104 }
Chris@16 105 else if(c <= a + fabs(a) * tol)
Chris@16 106 {
Chris@16 107 c = a + fabs(a) * tol;
Chris@16 108 }
Chris@16 109 else if(c >= b - fabs(b) * tol)
Chris@16 110 {
Chris@16 111 c = b - fabs(a) * tol;
Chris@16 112 }
Chris@16 113 //
Chris@16 114 // OK, lets invoke f(c):
Chris@16 115 //
Chris@16 116 T fc = f(c);
Chris@16 117 //
Chris@16 118 // if we have a zero then we have an exact solution to the root:
Chris@16 119 //
Chris@16 120 if(fc == 0)
Chris@16 121 {
Chris@16 122 a = c;
Chris@16 123 fa = 0;
Chris@16 124 d = 0;
Chris@16 125 fd = 0;
Chris@16 126 return;
Chris@16 127 }
Chris@16 128 //
Chris@16 129 // Non-zero fc, update the interval:
Chris@16 130 //
Chris@16 131 if(boost::math::sign(fa) * boost::math::sign(fc) < 0)
Chris@16 132 {
Chris@16 133 d = b;
Chris@16 134 fd = fb;
Chris@16 135 b = c;
Chris@16 136 fb = fc;
Chris@16 137 }
Chris@16 138 else
Chris@16 139 {
Chris@16 140 d = a;
Chris@16 141 fd = fa;
Chris@16 142 a = c;
Chris@16 143 fa= fc;
Chris@16 144 }
Chris@16 145 }
Chris@16 146
Chris@16 147 template <class T>
Chris@16 148 inline T safe_div(T num, T denom, T r)
Chris@16 149 {
Chris@16 150 //
Chris@16 151 // return num / denom without overflow,
Chris@16 152 // return r if overflow would occur.
Chris@16 153 //
Chris@16 154 BOOST_MATH_STD_USING // For ADL of std math functions
Chris@16 155
Chris@16 156 if(fabs(denom) < 1)
Chris@16 157 {
Chris@16 158 if(fabs(denom * tools::max_value<T>()) <= fabs(num))
Chris@16 159 return r;
Chris@16 160 }
Chris@16 161 return num / denom;
Chris@16 162 }
Chris@16 163
Chris@16 164 template <class T>
Chris@16 165 inline T secant_interpolate(const T& a, const T& b, const T& fa, const T& fb)
Chris@16 166 {
Chris@16 167 //
Chris@16 168 // Performs standard secant interpolation of [a,b] given
Chris@16 169 // function evaluations f(a) and f(b). Performs a bisection
Chris@16 170 // if secant interpolation would leave us very close to either
Chris@16 171 // a or b. Rationale: we only call this function when at least
Chris@16 172 // one other form of interpolation has already failed, so we know
Chris@16 173 // that the function is unlikely to be smooth with a root very
Chris@16 174 // close to a or b.
Chris@16 175 //
Chris@16 176 BOOST_MATH_STD_USING // For ADL of std math functions
Chris@16 177
Chris@16 178 T tol = tools::epsilon<T>() * 5;
Chris@16 179 T c = a - (fa / (fb - fa)) * (b - a);
Chris@16 180 if((c <= a + fabs(a) * tol) || (c >= b - fabs(b) * tol))
Chris@16 181 return (a + b) / 2;
Chris@16 182 return c;
Chris@16 183 }
Chris@16 184
Chris@16 185 template <class T>
Chris@16 186 T quadratic_interpolate(const T& a, const T& b, T const& d,
Chris@16 187 const T& fa, const T& fb, T const& fd,
Chris@16 188 unsigned count)
Chris@16 189 {
Chris@16 190 //
Chris@16 191 // Performs quadratic interpolation to determine the next point,
Chris@16 192 // takes count Newton steps to find the location of the
Chris@16 193 // quadratic polynomial.
Chris@16 194 //
Chris@16 195 // Point d must lie outside of the interval [a,b], it is the third
Chris@16 196 // best approximation to the root, after a and b.
Chris@16 197 //
Chris@16 198 // Note: this does not guarentee to find a root
Chris@16 199 // inside [a, b], so we fall back to a secant step should
Chris@16 200 // the result be out of range.
Chris@16 201 //
Chris@16 202 // Start by obtaining the coefficients of the quadratic polynomial:
Chris@16 203 //
Chris@16 204 T B = safe_div(T(fb - fa), T(b - a), tools::max_value<T>());
Chris@16 205 T A = safe_div(T(fd - fb), T(d - b), tools::max_value<T>());
Chris@16 206 A = safe_div(T(A - B), T(d - a), T(0));
Chris@16 207
Chris@16 208 if(A == 0)
Chris@16 209 {
Chris@16 210 // failure to determine coefficients, try a secant step:
Chris@16 211 return secant_interpolate(a, b, fa, fb);
Chris@16 212 }
Chris@16 213 //
Chris@16 214 // Determine the starting point of the Newton steps:
Chris@16 215 //
Chris@16 216 T c;
Chris@16 217 if(boost::math::sign(A) * boost::math::sign(fa) > 0)
Chris@16 218 {
Chris@16 219 c = a;
Chris@16 220 }
Chris@16 221 else
Chris@16 222 {
Chris@16 223 c = b;
Chris@16 224 }
Chris@16 225 //
Chris@16 226 // Take the Newton steps:
Chris@16 227 //
Chris@16 228 for(unsigned i = 1; i <= count; ++i)
Chris@16 229 {
Chris@16 230 //c -= safe_div(B * c, (B + A * (2 * c - a - b)), 1 + c - a);
Chris@16 231 c -= safe_div(T(fa+(B+A*(c-b))*(c-a)), T(B + A * (2 * c - a - b)), T(1 + c - a));
Chris@16 232 }
Chris@16 233 if((c <= a) || (c >= b))
Chris@16 234 {
Chris@16 235 // Oops, failure, try a secant step:
Chris@16 236 c = secant_interpolate(a, b, fa, fb);
Chris@16 237 }
Chris@16 238 return c;
Chris@16 239 }
Chris@16 240
Chris@16 241 template <class T>
Chris@16 242 T cubic_interpolate(const T& a, const T& b, const T& d,
Chris@16 243 const T& e, const T& fa, const T& fb,
Chris@16 244 const T& fd, const T& fe)
Chris@16 245 {
Chris@16 246 //
Chris@16 247 // Uses inverse cubic interpolation of f(x) at points
Chris@16 248 // [a,b,d,e] to obtain an approximate root of f(x).
Chris@16 249 // Points d and e lie outside the interval [a,b]
Chris@16 250 // and are the third and forth best approximations
Chris@16 251 // to the root that we have found so far.
Chris@16 252 //
Chris@16 253 // Note: this does not guarentee to find a root
Chris@16 254 // inside [a, b], so we fall back to quadratic
Chris@16 255 // interpolation in case of an erroneous result.
Chris@16 256 //
Chris@16 257 BOOST_MATH_INSTRUMENT_CODE(" a = " << a << " b = " << b
Chris@16 258 << " d = " << d << " e = " << e << " fa = " << fa << " fb = " << fb
Chris@16 259 << " fd = " << fd << " fe = " << fe);
Chris@16 260 T q11 = (d - e) * fd / (fe - fd);
Chris@16 261 T q21 = (b - d) * fb / (fd - fb);
Chris@16 262 T q31 = (a - b) * fa / (fb - fa);
Chris@16 263 T d21 = (b - d) * fd / (fd - fb);
Chris@16 264 T d31 = (a - b) * fb / (fb - fa);
Chris@16 265 BOOST_MATH_INSTRUMENT_CODE(
Chris@16 266 "q11 = " << q11 << " q21 = " << q21 << " q31 = " << q31
Chris@16 267 << " d21 = " << d21 << " d31 = " << d31);
Chris@16 268 T q22 = (d21 - q11) * fb / (fe - fb);
Chris@16 269 T q32 = (d31 - q21) * fa / (fd - fa);
Chris@16 270 T d32 = (d31 - q21) * fd / (fd - fa);
Chris@16 271 T q33 = (d32 - q22) * fa / (fe - fa);
Chris@16 272 T c = q31 + q32 + q33 + a;
Chris@16 273 BOOST_MATH_INSTRUMENT_CODE(
Chris@16 274 "q22 = " << q22 << " q32 = " << q32 << " d32 = " << d32
Chris@16 275 << " q33 = " << q33 << " c = " << c);
Chris@16 276
Chris@16 277 if((c <= a) || (c >= b))
Chris@16 278 {
Chris@16 279 // Out of bounds step, fall back to quadratic interpolation:
Chris@16 280 c = quadratic_interpolate(a, b, d, fa, fb, fd, 3);
Chris@16 281 BOOST_MATH_INSTRUMENT_CODE(
Chris@16 282 "Out of bounds interpolation, falling back to quadratic interpolation. c = " << c);
Chris@16 283 }
Chris@16 284
Chris@16 285 return c;
Chris@16 286 }
Chris@16 287
Chris@16 288 } // namespace detail
Chris@16 289
Chris@16 290 template <class F, class T, class Tol, class Policy>
Chris@16 291 std::pair<T, T> toms748_solve(F f, const T& ax, const T& bx, const T& fax, const T& fbx, Tol tol, boost::uintmax_t& max_iter, const Policy& pol)
Chris@16 292 {
Chris@16 293 //
Chris@16 294 // Main entry point and logic for Toms Algorithm 748
Chris@16 295 // root finder.
Chris@16 296 //
Chris@16 297 BOOST_MATH_STD_USING // For ADL of std math functions
Chris@16 298
Chris@16 299 static const char* function = "boost::math::tools::toms748_solve<%1%>";
Chris@16 300
Chris@16 301 boost::uintmax_t count = max_iter;
Chris@16 302 T a, b, fa, fb, c, u, fu, a0, b0, d, fd, e, fe;
Chris@16 303 static const T mu = 0.5f;
Chris@16 304
Chris@16 305 // initialise a, b and fa, fb:
Chris@16 306 a = ax;
Chris@16 307 b = bx;
Chris@16 308 if(a >= b)
Chris@101 309 return boost::math::detail::pair_from_single(policies::raise_domain_error(
Chris@16 310 function,
Chris@101 311 "Parameters a and b out of order: a=%1%", a, pol));
Chris@16 312 fa = fax;
Chris@16 313 fb = fbx;
Chris@16 314
Chris@16 315 if(tol(a, b) || (fa == 0) || (fb == 0))
Chris@16 316 {
Chris@16 317 max_iter = 0;
Chris@16 318 if(fa == 0)
Chris@16 319 b = a;
Chris@16 320 else if(fb == 0)
Chris@16 321 a = b;
Chris@16 322 return std::make_pair(a, b);
Chris@16 323 }
Chris@16 324
Chris@16 325 if(boost::math::sign(fa) * boost::math::sign(fb) > 0)
Chris@101 326 return boost::math::detail::pair_from_single(policies::raise_domain_error(
Chris@16 327 function,
Chris@101 328 "Parameters a and b do not bracket the root: a=%1%", a, pol));
Chris@16 329 // dummy value for fd, e and fe:
Chris@16 330 fe = e = fd = 1e5F;
Chris@16 331
Chris@16 332 if(fa != 0)
Chris@16 333 {
Chris@16 334 //
Chris@16 335 // On the first step we take a secant step:
Chris@16 336 //
Chris@16 337 c = detail::secant_interpolate(a, b, fa, fb);
Chris@16 338 detail::bracket(f, a, b, c, fa, fb, d, fd);
Chris@16 339 --count;
Chris@16 340 BOOST_MATH_INSTRUMENT_CODE(" a = " << a << " b = " << b);
Chris@16 341
Chris@16 342 if(count && (fa != 0) && !tol(a, b))
Chris@16 343 {
Chris@16 344 //
Chris@16 345 // On the second step we take a quadratic interpolation:
Chris@16 346 //
Chris@16 347 c = detail::quadratic_interpolate(a, b, d, fa, fb, fd, 2);
Chris@16 348 e = d;
Chris@16 349 fe = fd;
Chris@16 350 detail::bracket(f, a, b, c, fa, fb, d, fd);
Chris@16 351 --count;
Chris@16 352 BOOST_MATH_INSTRUMENT_CODE(" a = " << a << " b = " << b);
Chris@16 353 }
Chris@16 354 }
Chris@16 355
Chris@16 356 while(count && (fa != 0) && !tol(a, b))
Chris@16 357 {
Chris@16 358 // save our brackets:
Chris@16 359 a0 = a;
Chris@16 360 b0 = b;
Chris@16 361 //
Chris@16 362 // Starting with the third step taken
Chris@16 363 // we can use either quadratic or cubic interpolation.
Chris@16 364 // Cubic interpolation requires that all four function values
Chris@16 365 // fa, fb, fd, and fe are distinct, should that not be the case
Chris@16 366 // then variable prof will get set to true, and we'll end up
Chris@16 367 // taking a quadratic step instead.
Chris@16 368 //
Chris@16 369 T min_diff = tools::min_value<T>() * 32;
Chris@16 370 bool prof = (fabs(fa - fb) < min_diff) || (fabs(fa - fd) < min_diff) || (fabs(fa - fe) < min_diff) || (fabs(fb - fd) < min_diff) || (fabs(fb - fe) < min_diff) || (fabs(fd - fe) < min_diff);
Chris@16 371 if(prof)
Chris@16 372 {
Chris@16 373 c = detail::quadratic_interpolate(a, b, d, fa, fb, fd, 2);
Chris@16 374 BOOST_MATH_INSTRUMENT_CODE("Can't take cubic step!!!!");
Chris@16 375 }
Chris@16 376 else
Chris@16 377 {
Chris@16 378 c = detail::cubic_interpolate(a, b, d, e, fa, fb, fd, fe);
Chris@16 379 }
Chris@16 380 //
Chris@16 381 // re-bracket, and check for termination:
Chris@16 382 //
Chris@16 383 e = d;
Chris@16 384 fe = fd;
Chris@16 385 detail::bracket(f, a, b, c, fa, fb, d, fd);
Chris@16 386 if((0 == --count) || (fa == 0) || tol(a, b))
Chris@16 387 break;
Chris@16 388 BOOST_MATH_INSTRUMENT_CODE(" a = " << a << " b = " << b);
Chris@16 389 //
Chris@16 390 // Now another interpolated step:
Chris@16 391 //
Chris@16 392 prof = (fabs(fa - fb) < min_diff) || (fabs(fa - fd) < min_diff) || (fabs(fa - fe) < min_diff) || (fabs(fb - fd) < min_diff) || (fabs(fb - fe) < min_diff) || (fabs(fd - fe) < min_diff);
Chris@16 393 if(prof)
Chris@16 394 {
Chris@16 395 c = detail::quadratic_interpolate(a, b, d, fa, fb, fd, 3);
Chris@16 396 BOOST_MATH_INSTRUMENT_CODE("Can't take cubic step!!!!");
Chris@16 397 }
Chris@16 398 else
Chris@16 399 {
Chris@16 400 c = detail::cubic_interpolate(a, b, d, e, fa, fb, fd, fe);
Chris@16 401 }
Chris@16 402 //
Chris@16 403 // Bracket again, and check termination condition, update e:
Chris@16 404 //
Chris@16 405 detail::bracket(f, a, b, c, fa, fb, d, fd);
Chris@16 406 if((0 == --count) || (fa == 0) || tol(a, b))
Chris@16 407 break;
Chris@16 408 BOOST_MATH_INSTRUMENT_CODE(" a = " << a << " b = " << b);
Chris@16 409 //
Chris@16 410 // Now we take a double-length secant step:
Chris@16 411 //
Chris@16 412 if(fabs(fa) < fabs(fb))
Chris@16 413 {
Chris@16 414 u = a;
Chris@16 415 fu = fa;
Chris@16 416 }
Chris@16 417 else
Chris@16 418 {
Chris@16 419 u = b;
Chris@16 420 fu = fb;
Chris@16 421 }
Chris@16 422 c = u - 2 * (fu / (fb - fa)) * (b - a);
Chris@16 423 if(fabs(c - u) > (b - a) / 2)
Chris@16 424 {
Chris@16 425 c = a + (b - a) / 2;
Chris@16 426 }
Chris@16 427 //
Chris@16 428 // Bracket again, and check termination condition:
Chris@16 429 //
Chris@16 430 e = d;
Chris@16 431 fe = fd;
Chris@16 432 detail::bracket(f, a, b, c, fa, fb, d, fd);
Chris@16 433 BOOST_MATH_INSTRUMENT_CODE(" a = " << a << " b = " << b);
Chris@16 434 BOOST_MATH_INSTRUMENT_CODE(" tol = " << T((fabs(a) - fabs(b)) / fabs(a)));
Chris@16 435 if((0 == --count) || (fa == 0) || tol(a, b))
Chris@16 436 break;
Chris@16 437 //
Chris@16 438 // And finally... check to see if an additional bisection step is
Chris@16 439 // to be taken, we do this if we're not converging fast enough:
Chris@16 440 //
Chris@16 441 if((b - a) < mu * (b0 - a0))
Chris@16 442 continue;
Chris@16 443 //
Chris@16 444 // bracket again on a bisection:
Chris@16 445 //
Chris@16 446 e = d;
Chris@16 447 fe = fd;
Chris@16 448 detail::bracket(f, a, b, T(a + (b - a) / 2), fa, fb, d, fd);
Chris@16 449 --count;
Chris@16 450 BOOST_MATH_INSTRUMENT_CODE("Not converging: Taking a bisection!!!!");
Chris@16 451 BOOST_MATH_INSTRUMENT_CODE(" a = " << a << " b = " << b);
Chris@16 452 } // while loop
Chris@16 453
Chris@16 454 max_iter -= count;
Chris@16 455 if(fa == 0)
Chris@16 456 {
Chris@16 457 b = a;
Chris@16 458 }
Chris@16 459 else if(fb == 0)
Chris@16 460 {
Chris@16 461 a = b;
Chris@16 462 }
Chris@101 463 BOOST_MATH_LOG_COUNT(max_iter)
Chris@16 464 return std::make_pair(a, b);
Chris@16 465 }
Chris@16 466
Chris@16 467 template <class F, class T, class Tol>
Chris@16 468 inline std::pair<T, T> toms748_solve(F f, const T& ax, const T& bx, const T& fax, const T& fbx, Tol tol, boost::uintmax_t& max_iter)
Chris@16 469 {
Chris@16 470 return toms748_solve(f, ax, bx, fax, fbx, tol, max_iter, policies::policy<>());
Chris@16 471 }
Chris@16 472
Chris@16 473 template <class F, class T, class Tol, class Policy>
Chris@16 474 inline std::pair<T, T> toms748_solve(F f, const T& ax, const T& bx, Tol tol, boost::uintmax_t& max_iter, const Policy& pol)
Chris@16 475 {
Chris@16 476 max_iter -= 2;
Chris@16 477 std::pair<T, T> r = toms748_solve(f, ax, bx, f(ax), f(bx), tol, max_iter, pol);
Chris@16 478 max_iter += 2;
Chris@16 479 return r;
Chris@16 480 }
Chris@16 481
Chris@16 482 template <class F, class T, class Tol>
Chris@16 483 inline std::pair<T, T> toms748_solve(F f, const T& ax, const T& bx, Tol tol, boost::uintmax_t& max_iter)
Chris@16 484 {
Chris@16 485 return toms748_solve(f, ax, bx, tol, max_iter, policies::policy<>());
Chris@16 486 }
Chris@16 487
Chris@16 488 template <class F, class T, class Tol, class Policy>
Chris@16 489 std::pair<T, T> bracket_and_solve_root(F f, const T& guess, T factor, bool rising, Tol tol, boost::uintmax_t& max_iter, const Policy& pol)
Chris@16 490 {
Chris@16 491 BOOST_MATH_STD_USING
Chris@16 492 static const char* function = "boost::math::tools::bracket_and_solve_root<%1%>";
Chris@16 493 //
Chris@16 494 // Set up inital brackets:
Chris@16 495 //
Chris@16 496 T a = guess;
Chris@16 497 T b = a;
Chris@16 498 T fa = f(a);
Chris@16 499 T fb = fa;
Chris@16 500 //
Chris@16 501 // Set up invocation count:
Chris@16 502 //
Chris@16 503 boost::uintmax_t count = max_iter - 1;
Chris@16 504
Chris@101 505 int step = 32;
Chris@101 506
Chris@16 507 if((fa < 0) == (guess < 0 ? !rising : rising))
Chris@16 508 {
Chris@16 509 //
Chris@16 510 // Zero is to the right of b, so walk upwards
Chris@16 511 // until we find it:
Chris@16 512 //
Chris@16 513 while((boost::math::sign)(fb) == (boost::math::sign)(fa))
Chris@16 514 {
Chris@16 515 if(count == 0)
Chris@101 516 return boost::math::detail::pair_from_single(policies::raise_evaluation_error(function, "Unable to bracket root, last nearest value was %1%", b, pol));
Chris@16 517 //
Chris@101 518 // Heuristic: normally it's best not to increase the step sizes as we'll just end up
Chris@101 519 // with a really wide range to search for the root. However, if the initial guess was *really*
Chris@101 520 // bad then we need to speed up the search otherwise we'll take forever if we're orders of
Chris@101 521 // magnitude out. This happens most often if the guess is a small value (say 1) and the result
Chris@101 522 // we're looking for is close to std::numeric_limits<T>::min().
Chris@16 523 //
Chris@101 524 if((max_iter - count) % step == 0)
Chris@101 525 {
Chris@16 526 factor *= 2;
Chris@101 527 if(step > 1) step /= 2;
Chris@101 528 }
Chris@16 529 //
Chris@16 530 // Now go ahead and move our guess by "factor":
Chris@16 531 //
Chris@16 532 a = b;
Chris@16 533 fa = fb;
Chris@16 534 b *= factor;
Chris@16 535 fb = f(b);
Chris@16 536 --count;
Chris@16 537 BOOST_MATH_INSTRUMENT_CODE("a = " << a << " b = " << b << " fa = " << fa << " fb = " << fb << " count = " << count);
Chris@16 538 }
Chris@16 539 }
Chris@16 540 else
Chris@16 541 {
Chris@16 542 //
Chris@16 543 // Zero is to the left of a, so walk downwards
Chris@16 544 // until we find it:
Chris@16 545 //
Chris@16 546 while((boost::math::sign)(fb) == (boost::math::sign)(fa))
Chris@16 547 {
Chris@16 548 if(fabs(a) < tools::min_value<T>())
Chris@16 549 {
Chris@16 550 // Escape route just in case the answer is zero!
Chris@16 551 max_iter -= count;
Chris@16 552 max_iter += 1;
Chris@16 553 return a > 0 ? std::make_pair(T(0), T(a)) : std::make_pair(T(a), T(0));
Chris@16 554 }
Chris@16 555 if(count == 0)
Chris@101 556 return boost::math::detail::pair_from_single(policies::raise_evaluation_error(function, "Unable to bracket root, last nearest value was %1%", a, pol));
Chris@16 557 //
Chris@101 558 // Heuristic: normally it's best not to increase the step sizes as we'll just end up
Chris@101 559 // with a really wide range to search for the root. However, if the initial guess was *really*
Chris@101 560 // bad then we need to speed up the search otherwise we'll take forever if we're orders of
Chris@101 561 // magnitude out. This happens most often if the guess is a small value (say 1) and the result
Chris@101 562 // we're looking for is close to std::numeric_limits<T>::min().
Chris@16 563 //
Chris@101 564 if((max_iter - count) % step == 0)
Chris@101 565 {
Chris@16 566 factor *= 2;
Chris@101 567 if(step > 1) step /= 2;
Chris@101 568 }
Chris@16 569 //
Chris@16 570 // Now go ahead and move are guess by "factor":
Chris@16 571 //
Chris@16 572 b = a;
Chris@16 573 fb = fa;
Chris@16 574 a /= factor;
Chris@16 575 fa = f(a);
Chris@16 576 --count;
Chris@16 577 BOOST_MATH_INSTRUMENT_CODE("a = " << a << " b = " << b << " fa = " << fa << " fb = " << fb << " count = " << count);
Chris@16 578 }
Chris@16 579 }
Chris@16 580 max_iter -= count;
Chris@16 581 max_iter += 1;
Chris@16 582 std::pair<T, T> r = toms748_solve(
Chris@16 583 f,
Chris@16 584 (a < 0 ? b : a),
Chris@16 585 (a < 0 ? a : b),
Chris@16 586 (a < 0 ? fb : fa),
Chris@16 587 (a < 0 ? fa : fb),
Chris@16 588 tol,
Chris@16 589 count,
Chris@16 590 pol);
Chris@16 591 max_iter += count;
Chris@16 592 BOOST_MATH_INSTRUMENT_CODE("max_iter = " << max_iter << " count = " << count);
Chris@101 593 BOOST_MATH_LOG_COUNT(max_iter)
Chris@16 594 return r;
Chris@16 595 }
Chris@16 596
Chris@16 597 template <class F, class T, class Tol>
Chris@16 598 inline std::pair<T, T> bracket_and_solve_root(F f, const T& guess, const T& factor, bool rising, Tol tol, boost::uintmax_t& max_iter)
Chris@16 599 {
Chris@16 600 return bracket_and_solve_root(f, guess, factor, rising, tol, max_iter, policies::policy<>());
Chris@16 601 }
Chris@16 602
Chris@16 603 } // namespace tools
Chris@16 604 } // namespace math
Chris@16 605 } // namespace boost
Chris@16 606
Chris@16 607
Chris@16 608 #endif // BOOST_MATH_TOOLS_SOLVE_ROOT_HPP
Chris@16 609