toms748_solve.hpp

来自「Boost provides free peer-reviewed portab」· HPP 代码 · 共 585 行 · 第 1/2 页

HPP
585
字号
//  (C) Copyright John Maddock 2006.//  Use, modification and distribution are subject to the//  Boost Software License, Version 1.0. (See accompanying file//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)#ifndef BOOST_MATH_TOOLS_SOLVE_ROOT_HPP#define BOOST_MATH_TOOLS_SOLVE_ROOT_HPP#ifdef _MSC_VER#pragma once#endif#include <boost/math/tools/precision.hpp>#include <boost/math/policies/error_handling.hpp>#include <boost/math/tools/config.hpp>#include <boost/math/special_functions/sign.hpp>#include <boost/cstdint.hpp>#include <limits>namespace boost{ namespace math{ namespace tools{template <class T>class eps_tolerance{public:   eps_tolerance(unsigned bits)   {      BOOST_MATH_STD_USING      eps = (std::max)(T(ldexp(1.0F, 1-bits)), 2 * tools::epsilon<T>());   }   bool operator()(const T& a, const T& b)   {      BOOST_MATH_STD_USING      return (fabs(a - b) / (std::min)(fabs(a), fabs(b))) <= eps;   }private:   T eps;};struct equal_floor{   equal_floor(){}   template <class T>   bool operator()(const T& a, const T& b)   {      BOOST_MATH_STD_USING      return floor(a) == floor(b);   }};struct equal_ceil{   equal_ceil(){}   template <class T>   bool operator()(const T& a, const T& b)   {      BOOST_MATH_STD_USING      return ceil(a) == ceil(b);   }};struct equal_nearest_integer{   equal_nearest_integer(){}   template <class T>   bool operator()(const T& a, const T& b)   {      BOOST_MATH_STD_USING      return floor(a + 0.5f) == floor(b + 0.5f);   }};namespace detail{template <class F, class T>void bracket(F f, T& a, T& b, T c, T& fa, T& fb, T& d, T& fd){   //   // Given a point c inside the existing enclosing interval   // [a, b] sets a = c if f(c) == 0, otherwise finds the new    // enclosing interval: either [a, c] or [c, b] and sets   // d and fd to the point that has just been removed from   // the interval.  In other words d is the third best guess   // to the root.   //   BOOST_MATH_STD_USING  // For ADL of std math functions   T tol = tools::epsilon<T>() * 2;   //   // If the interval [a,b] is very small, or if c is too close    // to one end of the interval then we need to adjust the   // location of c accordingly:   //   if((b - a) < 2 * tol * a)   {      c = a + (b - a) / 2;   }   else if(c <= a + fabs(a) * tol)   {      c = a + fabs(a) * tol;   }   else if(c >= b - fabs(b) * tol)   {      c = b - fabs(a) * tol;   }   //   // OK, lets invoke f(c):   //   T fc = f(c);   //   // if we have a zero then we have an exact solution to the root:   //   if(fc == 0)   {      a = c;      fa = 0;      d = 0;      fd = 0;      return;   }   //   // Non-zero fc, update the interval:   //   if(boost::math::sign(fa) * boost::math::sign(fc) < 0)   {      d = b;      fd = fb;      b = c;      fb = fc;   }   else   {      d = a;      fd = fa;      a = c;      fa= fc;   }}template <class T>inline T safe_div(T num, T denom, T r){   //   // return num / denom without overflow,   // return r if overflow would occur.   //   BOOST_MATH_STD_USING  // For ADL of std math functions   if(fabs(denom) < 1)   {      if(fabs(denom * tools::max_value<T>()) <= fabs(num))         return r;   }   return num / denom;}template <class T>inline T secant_interpolate(const T& a, const T& b, const T& fa, const T& fb){   //   // Performs standard secant interpolation of [a,b] given   // function evaluations f(a) and f(b).  Performs a bisection   // if secant interpolation would leave us very close to either   // a or b.  Rationale: we only call this function when at least   // one other form of interpolation has already failed, so we know   // that the function is unlikely to be smooth with a root very   // close to a or b.   //   BOOST_MATH_STD_USING  // For ADL of std math functions   T tol = tools::epsilon<T>() * 5;   T c = a - (fa / (fb - fa)) * (b - a);   if((c <= a + fabs(a) * tol) || (c >= b - fabs(b) * tol))      return (a + b) / 2;   return c;}template <class T>T quadratic_interpolate(const T& a, const T& b, T const& d,                           const T& fa, const T& fb, T const& fd,                            unsigned count){   //   // Performs quadratic interpolation to determine the next point,   // takes count Newton steps to find the location of the   // quadratic polynomial.   //   // Point d must lie outside of the interval [a,b], it is the third   // best approximation to the root, after a and b.   //   // Note: this does not guarentee to find a root   // inside [a, b], so we fall back to a secant step should   // the result be out of range.   //   // Start by obtaining the coefficients of the quadratic polynomial:   //   T B = safe_div(fb - fa, b - a, tools::max_value<T>());   T A = safe_div(fd - fb, d - b, tools::max_value<T>());   A = safe_div(A - B, d - a, T(0));   if(a == 0)   {      // failure to determine coefficients, try a secant step:      return secant_interpolate(a, b, fa, fb);   }   //   // Determine the starting point of the Newton steps:   //   T c;   if(boost::math::sign(A) * boost::math::sign(fa) > 0)   {      c = a;   }   else   {      c = b;   }   //   // Take the Newton steps:   //   for(unsigned i = 1; i <= count; ++i)   {      //c -= safe_div(B * c, (B + A * (2 * c - a - b)), 1 + c - a);      c -= safe_div(fa+(B+A*(c-b))*(c-a), (B + A * (2 * c - a - b)), 1 + c - a);   }   if((c <= a) || (c >= b))   {      // Oops, failure, try a secant step:      c = secant_interpolate(a, b, fa, fb);   }   return c;}template <class T>T cubic_interpolate(const T& a, const T& b, const T& d,                     const T& e, const T& fa, const T& fb,                     const T& fd, const T& fe){   //   // Uses inverse cubic interpolation of f(x) at points    // [a,b,d,e] to obtain an approximate root of f(x).   // Points d and e lie outside the interval [a,b]   // and are the third and forth best approximations   // to the root that we have found so far.   //   // Note: this does not guarentee to find a root   // inside [a, b], so we fall back to quadratic   // interpolation in case of an erroneous result.   //   BOOST_MATH_INSTRUMENT_CODE(" a = " << a << " b = " << b      << " d = " << d << " e = " << e << " fa = " << fa << " fb = " << fb       << " fd = " << fd << " fe = " << fe);   T q11 = (d - e) * fd / (fe - fd);   T q21 = (b - d) * fb / (fd - fb);   T q31 = (a - b) * fa / (fb - fa);   T d21 = (b - d) * fd / (fd - fb);   T d31 = (a - b) * fb / (fb - fa);   BOOST_MATH_INSTRUMENT_CODE(      "q11 = " << q11 << " q21 = " << q21 << " q31 = " << q31      << " d21 = " << d21 << " d31 = " << d31);   T q22 = (d21 - q11) * fb / (fe - fb);   T q32 = (d31 - q21) * fa / (fd - fa);   T d32 = (d31 - q21) * fd / (fd - fa);   T q33 = (d32 - q22) * fa / (fe - fa);   T c = q31 + q32 + q33 + a;   BOOST_MATH_INSTRUMENT_CODE(      "q22 = " << q22 << " q32 = " << q32 << " d32 = " << d32      << " q33 = " << q33 << " c = " << c);   if((c <= a) || (c >= b))   {      // Out of bounds step, fall back to quadratic interpolation:      c = quadratic_interpolate(a, b, d, fa, fb, fd, 3);   BOOST_MATH_INSTRUMENT_CODE(      "Out of bounds interpolation, falling back to quadratic interpolation. c = " << c);   }   return c;}} // namespace detailtemplate <class F, class T, class Tol, class Policy>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){   //   // Main entry point and logic for Toms Algorithm 748   // root finder.   //   BOOST_MATH_STD_USING  // For ADL of std math functions   static const char* function = "boost::math::tools::toms748_solve<%1%>";   boost::uintmax_t count = max_iter;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?