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 + -
显示快捷键?