Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:40:42

0001 //  (C) Copyright John Maddock 2006.
0002 //  Use, modification and distribution are subject to the
0003 //  Boost Software License, Version 1.0. (See accompanying file
0004 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0005 
0006 #ifndef BOOST_MATH_TOOLS_NEWTON_SOLVER_HPP
0007 #define BOOST_MATH_TOOLS_NEWTON_SOLVER_HPP
0008 
0009 #ifdef _MSC_VER
0010 #pragma once
0011 #endif
0012 #include <boost/math/tools/complex.hpp> // test for multiprecision types in complex Newton
0013 
0014 #include <utility>
0015 #include <cmath>
0016 #include <tuple>
0017 #include <cstdint>
0018 
0019 #include <boost/math/tools/config.hpp>
0020 #include <boost/math/tools/cxx03_warn.hpp>
0021 
0022 #include <boost/math/special_functions/sign.hpp>
0023 #include <boost/math/special_functions/next.hpp>
0024 #include <boost/math/tools/toms748_solve.hpp>
0025 #include <boost/math/policies/error_handling.hpp>
0026 
0027 namespace boost {
0028 namespace math {
0029 namespace tools {
0030 
0031 namespace detail {
0032 
0033 namespace dummy {
0034 
0035    template<int n, class T>
0036    typename T::value_type get(const T&) BOOST_MATH_NOEXCEPT(T);
0037 }
0038 
0039 template <class Tuple, class T>
0040 void unpack_tuple(const Tuple& t, T& a, T& b) BOOST_MATH_NOEXCEPT(T)
0041 {
0042    using dummy::get;
0043    // Use ADL to find the right overload for get:
0044    a = get<0>(t);
0045    b = get<1>(t);
0046 }
0047 template <class Tuple, class T>
0048 void unpack_tuple(const Tuple& t, T& a, T& b, T& c) BOOST_MATH_NOEXCEPT(T)
0049 {
0050    using dummy::get;
0051    // Use ADL to find the right overload for get:
0052    a = get<0>(t);
0053    b = get<1>(t);
0054    c = get<2>(t);
0055 }
0056 
0057 template <class Tuple, class T>
0058 inline void unpack_0(const Tuple& t, T& val) BOOST_MATH_NOEXCEPT(T)
0059 {
0060    using dummy::get;
0061    // Rely on ADL to find the correct overload of get:
0062    val = get<0>(t);
0063 }
0064 
0065 template <class T, class U, class V>
0066 inline void unpack_tuple(const std::pair<T, U>& p, V& a, V& b) BOOST_MATH_NOEXCEPT(T)
0067 {
0068    a = p.first;
0069    b = p.second;
0070 }
0071 template <class T, class U, class V>
0072 inline void unpack_0(const std::pair<T, U>& p, V& a) BOOST_MATH_NOEXCEPT(T)
0073 {
0074    a = p.first;
0075 }
0076 
0077 template <class F, class T>
0078 void handle_zero_derivative(F f,
0079    T& last_f0,
0080    const T& f0,
0081    T& delta,
0082    T& result,
0083    T& guess,
0084    const T& min,
0085    const T& max) noexcept(BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
0086 {
0087    if (last_f0 == 0)
0088    {
0089       // this must be the first iteration, pretend that we had a
0090       // previous one at either min or max:
0091       if (result == min)
0092       {
0093          guess = max;
0094       }
0095       else
0096       {
0097          guess = min;
0098       }
0099       unpack_0(f(guess), last_f0);
0100       delta = guess - result;
0101    }
0102    if (sign(last_f0) * sign(f0) < 0)
0103    {
0104       // we've crossed over so move in opposite direction to last step:
0105       if (delta < 0)
0106       {
0107          delta = (result - min) / 2;
0108       }
0109       else
0110       {
0111          delta = (result - max) / 2;
0112       }
0113    }
0114    else
0115    {
0116       // move in same direction as last step:
0117       if (delta < 0)
0118       {
0119          delta = (result - max) / 2;
0120       }
0121       else
0122       {
0123          delta = (result - min) / 2;
0124       }
0125    }
0126 }
0127 
0128 } // namespace
0129 
0130 template <class F, class T, class Tol, class Policy>
0131 std::pair<T, T> bisect(F f, T min, T max, Tol tol, std::uintmax_t& max_iter, const Policy& pol) noexcept(policies::is_noexcept_error_policy<Policy>::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
0132 {
0133    T fmin = f(min);
0134    T fmax = f(max);
0135    if (fmin == 0)
0136    {
0137       max_iter = 2;
0138       return std::make_pair(min, min);
0139    }
0140    if (fmax == 0)
0141    {
0142       max_iter = 2;
0143       return std::make_pair(max, max);
0144    }
0145 
0146    //
0147    // Error checking:
0148    //
0149    static const char* function = "boost::math::tools::bisect<%1%>";
0150    if (min >= max)
0151    {
0152       return boost::math::detail::pair_from_single(policies::raise_evaluation_error(function,
0153          "Arguments in wrong order in boost::math::tools::bisect (first arg=%1%)", min, pol));
0154    }
0155    if (fmin * fmax >= 0)
0156    {
0157       return boost::math::detail::pair_from_single(policies::raise_evaluation_error(function,
0158          "No change of sign in boost::math::tools::bisect, either there is no root to find, or there are multiple roots in the interval (f(min) = %1%).", fmin, pol));
0159    }
0160 
0161    //
0162    // Three function invocations so far:
0163    //
0164    std::uintmax_t count = max_iter;
0165    if (count < 3)
0166       count = 0;
0167    else
0168       count -= 3;
0169 
0170    while (count && (0 == tol(min, max)))
0171    {
0172       T mid = (min + max) / 2;
0173       T fmid = f(mid);
0174       if ((mid == max) || (mid == min))
0175          break;
0176       if (fmid == 0)
0177       {
0178          min = max = mid;
0179          break;
0180       }
0181       else if (sign(fmid) * sign(fmin) < 0)
0182       {
0183          max = mid;
0184       }
0185       else
0186       {
0187          min = mid;
0188          fmin = fmid;
0189       }
0190       --count;
0191    }
0192 
0193    max_iter -= count;
0194 
0195 #ifdef BOOST_MATH_INSTRUMENT
0196    std::cout << "Bisection required " << max_iter << " iterations.\n";
0197 #endif
0198 
0199    return std::make_pair(min, max);
0200 }
0201 
0202 template <class F, class T, class Tol>
0203 inline std::pair<T, T> bisect(F f, T min, T max, Tol tol, std::uintmax_t& max_iter)  noexcept(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
0204 {
0205    return bisect(f, min, max, tol, max_iter, policies::policy<>());
0206 }
0207 
0208 template <class F, class T, class Tol>
0209 inline std::pair<T, T> bisect(F f, T min, T max, Tol tol) noexcept(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
0210 {
0211    std::uintmax_t m = (std::numeric_limits<std::uintmax_t>::max)();
0212    return bisect(f, min, max, tol, m, policies::policy<>());
0213 }
0214 
0215 
0216 template <class F, class T>
0217 T newton_raphson_iterate(F f, T guess, T min, T max, int digits, std::uintmax_t& max_iter) noexcept(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
0218 {
0219    BOOST_MATH_STD_USING
0220 
0221    static const char* function = "boost::math::tools::newton_raphson_iterate<%1%>";
0222    if (min > max)
0223    {
0224       return policies::raise_evaluation_error(function, "Range arguments in wrong order in boost::math::tools::newton_raphson_iterate(first arg=%1%)", min, boost::math::policies::policy<>());
0225    }
0226 
0227    T f0(0), f1, last_f0(0);
0228    T result = guess;
0229 
0230    T factor = static_cast<T>(ldexp(1.0, 1 - digits));
0231    T delta = tools::max_value<T>();
0232    T delta1 = tools::max_value<T>();
0233    T delta2 = tools::max_value<T>();
0234 
0235    //
0236    // We use these to sanity check that we do actually bracket a root,
0237    // we update these to the function value when we update the endpoints
0238    // of the range.  Then, provided at some point we update both endpoints
0239    // checking that max_range_f * min_range_f <= 0 verifies there is a root
0240    // to be found somewhere.  Note that if there is no root, and we approach 
0241    // a local minima, then the derivative will go to zero, and hence the next
0242    // step will jump out of bounds (or at least past the minima), so this
0243    // check *should* happen in pathological cases.
0244    //
0245    T max_range_f = 0;
0246    T min_range_f = 0;
0247 
0248    std::uintmax_t count(max_iter);
0249 
0250 #ifdef BOOST_MATH_INSTRUMENT
0251    std::cout << "Newton_raphson_iterate, guess = " << guess << ", min = " << min << ", max = " << max
0252       << ", digits = " << digits << ", max_iter = " << max_iter << "\n";
0253 #endif
0254 
0255    do {
0256       last_f0 = f0;
0257       delta2 = delta1;
0258       delta1 = delta;
0259       detail::unpack_tuple(f(result), f0, f1);
0260       --count;
0261       if (0 == f0)
0262          break;
0263       if (f1 == 0)
0264       {
0265          // Oops zero derivative!!!
0266          detail::handle_zero_derivative(f, last_f0, f0, delta, result, guess, min, max);
0267       }
0268       else
0269       {
0270          delta = f0 / f1;
0271       }
0272 #ifdef BOOST_MATH_INSTRUMENT
0273       std::cout << "Newton iteration " << max_iter - count << ", delta = " << delta << ", residual = " << f0 << "\n";
0274 #endif
0275       if (fabs(delta * 2) > fabs(delta2))
0276       {
0277          // Last two steps haven't converged.
0278          delta = (delta > 0) ? (result - min) / 2 : (result - max) / 2;
0279          // reset delta1/2 so we don't take this branch next time round:
0280          delta1 = 3 * delta;
0281          delta2 = 3 * delta;
0282       }
0283       guess = result;
0284       result -= delta;
0285       if (result <= min)
0286       {
0287          delta = 0.5F * (guess - min);
0288          result = guess - delta;
0289          if ((result == min) || (result == max))
0290             break;
0291       }
0292       else if (result >= max)
0293       {
0294          delta = 0.5F * (guess - max);
0295          result = guess - delta;
0296          if ((result == min) || (result == max))
0297             break;
0298       }
0299       // Update brackets:
0300       if (delta > 0)
0301       {
0302          max = guess;
0303          max_range_f = f0;
0304       }
0305       else
0306       {
0307          min = guess;
0308          min_range_f = f0;
0309       }
0310       //
0311       // Sanity check that we bracket the root:
0312       //
0313       if (max_range_f * min_range_f > 0)
0314       {
0315          return policies::raise_evaluation_error(function, "There appears to be no root to be found in boost::math::tools::newton_raphson_iterate, perhaps we have a local minima near current best guess of %1%", guess, boost::math::policies::policy<>());
0316       }
0317    }while(count && (fabs(result * factor) < fabs(delta)));
0318 
0319    max_iter -= count;
0320 
0321 #ifdef BOOST_MATH_INSTRUMENT
0322    std::cout << "Newton Raphson required " << max_iter << " iterations\n";
0323 #endif
0324 
0325    return result;
0326 }
0327 
0328 template <class F, class T>
0329 inline T newton_raphson_iterate(F f, T guess, T min, T max, int digits) noexcept(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
0330 {
0331    std::uintmax_t m = (std::numeric_limits<std::uintmax_t>::max)();
0332    return newton_raphson_iterate(f, guess, min, max, digits, m);
0333 }
0334 
0335 namespace detail {
0336 
0337    struct halley_step
0338    {
0339       template <class T>
0340       static T step(const T& /*x*/, const T& f0, const T& f1, const T& f2) noexcept(BOOST_MATH_IS_FLOAT(T))
0341       {
0342          using std::fabs;
0343          T denom = 2 * f0;
0344          T num = 2 * f1 - f0 * (f2 / f1);
0345          T delta;
0346 
0347          BOOST_MATH_INSTRUMENT_VARIABLE(denom);
0348          BOOST_MATH_INSTRUMENT_VARIABLE(num);
0349 
0350          if ((fabs(num) < 1) && (fabs(denom) >= fabs(num) * tools::max_value<T>()))
0351          {
0352             // possible overflow, use Newton step:
0353             delta = f0 / f1;
0354          }
0355          else
0356             delta = denom / num;
0357          return delta;
0358       }
0359    };
0360 
0361    template <class F, class T>
0362    T bracket_root_towards_min(F f, T guess, const T& f0, T& min, T& max, std::uintmax_t& count) noexcept(BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())));
0363 
0364    template <class F, class T>
0365    T bracket_root_towards_max(F f, T guess, const T& f0, T& min, T& max, std::uintmax_t& count) noexcept(BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
0366    {
0367       using std::fabs;
0368       using std::ldexp;
0369       using std::abs;
0370       using std::frexp;
0371       if(count < 2)
0372          return guess - (max + min) / 2; // Not enough counts left to do anything!!
0373       //
0374       // Move guess towards max until we bracket the root, updating min and max as we go:
0375       //
0376       int e;
0377       frexp(max / guess, &e);
0378       e = abs(e);
0379       T guess0 = guess;
0380       T multiplier = e < 64 ? static_cast<T>(2) : static_cast<T>(ldexp(T(1), e / 32));
0381       T f_current = f0;
0382       if (fabs(min) < fabs(max))
0383       {
0384          while (--count && ((f_current < 0) == (f0 < 0)))
0385          {
0386             min = guess;
0387             guess *= multiplier;
0388             if (guess > max)
0389             {
0390                guess = max;
0391                f_current = -f_current;  // There must be a change of sign!
0392                break;
0393             }
0394             multiplier *= e > 1024 ? 8 : 2;
0395             unpack_0(f(guess), f_current);
0396          }
0397       }
0398       else
0399       {
0400          //
0401          // If min and max are negative we have to divide to head towards max:
0402          //
0403          while (--count && ((f_current < 0) == (f0 < 0)))
0404          {
0405             min = guess;
0406             guess /= multiplier;
0407             if (guess > max)
0408             {
0409                guess = max;
0410                f_current = -f_current;  // There must be a change of sign!
0411                break;
0412             }
0413             multiplier *= e > 1024 ? 8 : 2;
0414             unpack_0(f(guess), f_current);
0415          }
0416       }
0417 
0418       if (count)
0419       {
0420          max = guess;
0421          if (multiplier > 16)
0422             return (guess0 - guess) + bracket_root_towards_min(f, guess, f_current, min, max, count);
0423       }
0424       return guess0 - (max + min) / 2;
0425    }
0426 
0427    template <class F, class T>
0428    T bracket_root_towards_min(F f, T guess, const T& f0, T& min, T& max, std::uintmax_t& count) noexcept(BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
0429    {
0430       using std::fabs;
0431       using std::ldexp;
0432       using std::abs;
0433       using std::frexp;
0434       if (count < 2)
0435          return guess - (max + min) / 2; // Not enough counts left to do anything!!
0436       //
0437       // Move guess towards min until we bracket the root, updating min and max as we go:
0438       //
0439       int e;
0440       frexp(guess / min, &e);
0441       e = abs(e);
0442       T guess0 = guess;
0443       T multiplier = e < 64 ? static_cast<T>(2) : static_cast<T>(ldexp(T(1), e / 32));
0444       T f_current = f0;
0445 
0446       if (fabs(min) < fabs(max))
0447       {
0448          while (--count && ((f_current < 0) == (f0 < 0)))
0449          {
0450             max = guess;
0451             guess /= multiplier;
0452             if (guess < min)
0453             {
0454                guess = min;
0455                f_current = -f_current;  // There must be a change of sign!
0456                break;
0457             }
0458             multiplier *= e > 1024 ? 8 : 2;
0459             unpack_0(f(guess), f_current);
0460          }
0461       }
0462       else
0463       {
0464          //
0465          // If min and max are negative we have to multiply to head towards min:
0466          //
0467          while (--count && ((f_current < 0) == (f0 < 0)))
0468          {
0469             max = guess;
0470             guess *= multiplier;
0471             if (guess < min)
0472             {
0473                guess = min;
0474                f_current = -f_current;  // There must be a change of sign!
0475                break;
0476             }
0477             multiplier *= e > 1024 ? 8 : 2;
0478             unpack_0(f(guess), f_current);
0479          }
0480       }
0481 
0482       if (count)
0483       {
0484          min = guess;
0485          if (multiplier > 16)
0486             return (guess0 - guess) + bracket_root_towards_max(f, guess, f_current, min, max, count);
0487       }
0488       return guess0 - (max + min) / 2;
0489    }
0490 
0491    template <class Stepper, class F, class T>
0492    T second_order_root_finder(F f, T guess, T min, T max, int digits, std::uintmax_t& max_iter) noexcept(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
0493    {
0494       BOOST_MATH_STD_USING
0495 
0496 #ifdef BOOST_MATH_INSTRUMENT
0497         std::cout << "Second order root iteration, guess = " << guess << ", min = " << min << ", max = " << max
0498         << ", digits = " << digits << ", max_iter = " << max_iter << "\n";
0499 #endif
0500       static const char* function = "boost::math::tools::halley_iterate<%1%>";
0501       if (min >= max)
0502       {
0503          return policies::raise_evaluation_error(function, "Range arguments in wrong order in boost::math::tools::halley_iterate(first arg=%1%)", min, boost::math::policies::policy<>());
0504       }
0505 
0506       T f0(0), f1, f2;
0507       T result = guess;
0508 
0509       T factor = ldexp(static_cast<T>(1.0), 1 - digits);
0510       T delta = (std::max)(T(10000000 * guess), T(10000000));  // arbitrarily large delta
0511       T last_f0 = 0;
0512       T delta1 = delta;
0513       T delta2 = delta;
0514       bool out_of_bounds_sentry = false;
0515 
0516    #ifdef BOOST_MATH_INSTRUMENT
0517       std::cout << "Second order root iteration, limit = " << factor << "\n";
0518    #endif
0519 
0520       //
0521       // We use these to sanity check that we do actually bracket a root,
0522       // we update these to the function value when we update the endpoints
0523       // of the range.  Then, provided at some point we update both endpoints
0524       // checking that max_range_f * min_range_f <= 0 verifies there is a root
0525       // to be found somewhere.  Note that if there is no root, and we approach 
0526       // a local minima, then the derivative will go to zero, and hence the next
0527       // step will jump out of bounds (or at least past the minima), so this
0528       // check *should* happen in pathological cases.
0529       //
0530       T max_range_f = 0;
0531       T min_range_f = 0;
0532 
0533       std::uintmax_t count(max_iter);
0534 
0535       do {
0536          last_f0 = f0;
0537          delta2 = delta1;
0538          delta1 = delta;
0539 #ifndef BOOST_NO_EXCEPTIONS
0540          try
0541 #endif
0542          {
0543             detail::unpack_tuple(f(result), f0, f1, f2);
0544          }
0545 #ifndef BOOST_NO_EXCEPTIONS
0546          catch (const std::overflow_error&)
0547          {
0548             f0 = max > 0 ? tools::max_value<T>() : -tools::min_value<T>();
0549             f1 = f2 = 0;
0550          }
0551 #endif
0552          --count;
0553 
0554          BOOST_MATH_INSTRUMENT_VARIABLE(f0);
0555          BOOST_MATH_INSTRUMENT_VARIABLE(f1);
0556          BOOST_MATH_INSTRUMENT_VARIABLE(f2);
0557 
0558          if (0 == f0)
0559             break;
0560          if (f1 == 0)
0561          {
0562             // Oops zero derivative!!!
0563             detail::handle_zero_derivative(f, last_f0, f0, delta, result, guess, min, max);
0564          }
0565          else
0566          {
0567             if (f2 != 0)
0568             {
0569                delta = Stepper::step(result, f0, f1, f2);
0570                if (delta * f1 / f0 < 0)
0571                {
0572                   // Oh dear, we have a problem as Newton and Halley steps
0573                   // disagree about which way we should move.  Probably
0574                   // there is cancelation error in the calculation of the
0575                   // Halley step, or else the derivatives are so small
0576                   // that their values are basically trash.  We will move
0577                   // in the direction indicated by a Newton step, but
0578                   // by no more than twice the current guess value, otherwise
0579                   // we can jump way out of bounds if we're not careful.
0580                   // See https://svn.boost.org/trac/boost/ticket/8314.
0581                   delta = f0 / f1;
0582                   if (fabs(delta) > 2 * fabs(result))
0583                      delta = (delta < 0 ? -1 : 1) * 2 * fabs(result);
0584                }
0585             }
0586             else
0587                delta = f0 / f1;
0588          }
0589    #ifdef BOOST_MATH_INSTRUMENT
0590          std::cout << "Second order root iteration, delta = " << delta << ", residual = " << f0 << "\n";
0591    #endif
0592          // We need to avoid delta/delta2 overflowing here:
0593          T convergence = (fabs(delta2) > 1) || (fabs(tools::max_value<T>() * delta2) > fabs(delta)) ? fabs(delta / delta2) : tools::max_value<T>();
0594          if ((convergence > 0.8) && (convergence < 2))
0595          {
0596             // last two steps haven't converged.
0597             if (fabs(min) < 1 ? fabs(1000 * min) < fabs(max) : fabs(max / min) > 1000)
0598             {
0599                if(delta > 0)
0600                   delta = bracket_root_towards_min(f, result, f0, min, max, count);
0601                else
0602                   delta = bracket_root_towards_max(f, result, f0, min, max, count);
0603             }
0604             else
0605             {
0606                delta = (delta > 0) ? (result - min) / 2 : (result - max) / 2;
0607                if ((result != 0) && (fabs(delta) > result))
0608                   delta = sign(delta) * fabs(result) * 0.9f; // protect against huge jumps!
0609             }
0610             // reset delta2 so that this branch will *not* be taken on the
0611             // next iteration:
0612             delta2 = delta * 3;
0613             delta1 = delta * 3;
0614             BOOST_MATH_INSTRUMENT_VARIABLE(delta);
0615          }
0616          guess = result;
0617          result -= delta;
0618          BOOST_MATH_INSTRUMENT_VARIABLE(result);
0619 
0620          // check for out of bounds step:
0621          if (result < min)
0622          {
0623             T diff = ((fabs(min) < 1) && (fabs(result) > 1) && (tools::max_value<T>() / fabs(result) < fabs(min)))
0624                ? T(1000)
0625                : (fabs(min) < 1) && (fabs(tools::max_value<T>() * min) < fabs(result))
0626                ? ((min < 0) != (result < 0)) ? -tools::max_value<T>() : tools::max_value<T>() : T(result / min);
0627             if (fabs(diff) < 1)
0628                diff = 1 / diff;
0629             if (!out_of_bounds_sentry && (diff > 0) && (diff < 3))
0630             {
0631                // Only a small out of bounds step, lets assume that the result
0632                // is probably approximately at min:
0633                delta = 0.99f * (guess - min);
0634                result = guess - delta;
0635                out_of_bounds_sentry = true; // only take this branch once!
0636             }
0637             else
0638             {
0639                if (fabs(float_distance(min, max)) < 2)
0640                {
0641                   result = guess = (min + max) / 2;
0642                   break;
0643                }
0644                delta = bracket_root_towards_min(f, guess, f0, min, max, count);
0645                result = guess - delta;
0646                if (result <= min)
0647                   result = float_next(min);
0648                if (result >= max)
0649                   result = float_prior(max);
0650                guess = min;
0651                continue;
0652             }
0653          }
0654          else if (result > max)
0655          {
0656             T diff = ((fabs(max) < 1) && (fabs(result) > 1) && (tools::max_value<T>() / fabs(result) < fabs(max))) ? T(1000) : T(result / max);
0657             if (fabs(diff) < 1)
0658                diff = 1 / diff;
0659             if (!out_of_bounds_sentry && (diff > 0) && (diff < 3))
0660             {
0661                // Only a small out of bounds step, lets assume that the result
0662                // is probably approximately at min:
0663                delta = 0.99f * (guess - max);
0664                result = guess - delta;
0665                out_of_bounds_sentry = true; // only take this branch once!
0666             }
0667             else
0668             {
0669                if (fabs(float_distance(min, max)) < 2)
0670                {
0671                   result = guess = (min + max) / 2;
0672                   break;
0673                }
0674                delta = bracket_root_towards_max(f, guess, f0, min, max, count);
0675                result = guess - delta;
0676                if (result >= max)
0677                   result = float_prior(max);
0678                if (result <= min)
0679                   result = float_next(min);
0680                guess = min;
0681                continue;
0682             }
0683          }
0684          // update brackets:
0685          if (delta > 0)
0686          {
0687             max = guess;
0688             max_range_f = f0;
0689          }
0690          else
0691          {
0692             min = guess;
0693             min_range_f = f0;
0694          }
0695          //
0696          // Sanity check that we bracket the root:
0697          //
0698          if (max_range_f * min_range_f > 0)
0699          {
0700             return policies::raise_evaluation_error(function, "There appears to be no root to be found in boost::math::tools::newton_raphson_iterate, perhaps we have a local minima near current best guess of %1%", guess, boost::math::policies::policy<>());
0701          }
0702       } while(count && (fabs(result * factor) < fabs(delta)));
0703 
0704       max_iter -= count;
0705 
0706    #ifdef BOOST_MATH_INSTRUMENT
0707       std::cout << "Second order root finder required " << max_iter << " iterations.\n";
0708    #endif
0709 
0710       return result;
0711    }
0712 } // T second_order_root_finder
0713 
0714 template <class F, class T>
0715 T halley_iterate(F f, T guess, T min, T max, int digits, std::uintmax_t& max_iter) noexcept(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
0716 {
0717    return detail::second_order_root_finder<detail::halley_step>(f, guess, min, max, digits, max_iter);
0718 }
0719 
0720 template <class F, class T>
0721 inline T halley_iterate(F f, T guess, T min, T max, int digits) noexcept(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
0722 {
0723    std::uintmax_t m = (std::numeric_limits<std::uintmax_t>::max)();
0724    return halley_iterate(f, guess, min, max, digits, m);
0725 }
0726 
0727 namespace detail {
0728 
0729    struct schroder_stepper
0730    {
0731       template <class T>
0732       static T step(const T& x, const T& f0, const T& f1, const T& f2) noexcept(BOOST_MATH_IS_FLOAT(T))
0733       {
0734          using std::fabs;
0735          T ratio = f0 / f1;
0736          T delta;
0737          if ((x != 0) && (fabs(ratio / x) < 0.1))
0738          {
0739             delta = ratio + (f2 / (2 * f1)) * ratio * ratio;
0740             // check second derivative doesn't over compensate:
0741             if (delta * ratio < 0)
0742                delta = ratio;
0743          }
0744          else
0745             delta = ratio;  // fall back to Newton iteration.
0746          return delta;
0747       }
0748    };
0749 
0750 }
0751 
0752 template <class F, class T>
0753 T schroder_iterate(F f, T guess, T min, T max, int digits, std::uintmax_t& max_iter) noexcept(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
0754 {
0755    return detail::second_order_root_finder<detail::schroder_stepper>(f, guess, min, max, digits, max_iter);
0756 }
0757 
0758 template <class F, class T>
0759 inline T schroder_iterate(F f, T guess, T min, T max, int digits) noexcept(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
0760 {
0761    std::uintmax_t m = (std::numeric_limits<std::uintmax_t>::max)();
0762    return schroder_iterate(f, guess, min, max, digits, m);
0763 }
0764 //
0765 // These two are the old spelling of this function, retained for backwards compatibility just in case:
0766 //
0767 template <class F, class T>
0768 T schroeder_iterate(F f, T guess, T min, T max, int digits, std::uintmax_t& max_iter) noexcept(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
0769 {
0770    return detail::second_order_root_finder<detail::schroder_stepper>(f, guess, min, max, digits, max_iter);
0771 }
0772 
0773 template <class F, class T>
0774 inline T schroeder_iterate(F f, T guess, T min, T max, int digits) noexcept(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
0775 {
0776    std::uintmax_t m = (std::numeric_limits<std::uintmax_t>::max)();
0777    return schroder_iterate(f, guess, min, max, digits, m);
0778 }
0779 
0780 #ifndef BOOST_NO_CXX11_AUTO_DECLARATIONS
0781 /*
0782    * Why do we set the default maximum number of iterations to the number of digits in the type?
0783    * Because for double roots, the number of digits increases linearly with the number of iterations,
0784    * so this default should recover full precision even in this somewhat pathological case.
0785    * For isolated roots, the problem is so rapidly convergent that this doesn't matter at all.
0786    */
0787 template<class Complex, class F>
0788 Complex complex_newton(F g, Complex guess, int max_iterations = std::numeric_limits<typename Complex::value_type>::digits)
0789 {
0790    typedef typename Complex::value_type Real;
0791    using std::norm;
0792    using std::abs;
0793    using std::max;
0794    // z0, z1, and z2 cannot be the same, in case we immediately need to resort to Muller's Method:
0795    Complex z0 = guess + Complex(1, 0);
0796    Complex z1 = guess + Complex(0, 1);
0797    Complex z2 = guess;
0798 
0799    do {
0800       auto pair = g(z2);
0801       if (norm(pair.second) == 0)
0802       {
0803          // Muller's method. Notation follows Numerical Recipes, 9.5.2:
0804          Complex q = (z2 - z1) / (z1 - z0);
0805          auto P0 = g(z0);
0806          auto P1 = g(z1);
0807          Complex qp1 = static_cast<Complex>(1) + q;
0808          Complex A = q * (pair.first - qp1 * P1.first + q * P0.first);
0809 
0810          Complex B = (static_cast<Complex>(2) * q + static_cast<Complex>(1)) * pair.first - qp1 * qp1 * P1.first + q * q * P0.first;
0811          Complex C = qp1 * pair.first;
0812          Complex rad = sqrt(B * B - static_cast<Complex>(4) * A * C);
0813          Complex denom1 = B + rad;
0814          Complex denom2 = B - rad;
0815          Complex correction = (z1 - z2) * static_cast<Complex>(2) * C;
0816          if (norm(denom1) > norm(denom2))
0817          {
0818             correction /= denom1;
0819          }
0820          else
0821          {
0822             correction /= denom2;
0823          }
0824 
0825          z0 = z1;
0826          z1 = z2;
0827          z2 = z2 + correction;
0828       }
0829       else
0830       {
0831          z0 = z1;
0832          z1 = z2;
0833          z2 = z2 - (pair.first / pair.second);
0834       }
0835 
0836       // See: https://math.stackexchange.com/questions/3017766/constructing-newton-iteration-converging-to-non-root
0837       // If f' is continuous, then convergence of x_n -> x* implies f(x*) = 0.
0838       // This condition approximates this convergence condition by requiring three consecutive iterates to be clustered.
0839       Real tol = (max)(abs(z2) * std::numeric_limits<Real>::epsilon(), std::numeric_limits<Real>::epsilon());
0840       bool real_close = abs(z0.real() - z1.real()) < tol && abs(z0.real() - z2.real()) < tol && abs(z1.real() - z2.real()) < tol;
0841       bool imag_close = abs(z0.imag() - z1.imag()) < tol && abs(z0.imag() - z2.imag()) < tol && abs(z1.imag() - z2.imag()) < tol;
0842       if (real_close && imag_close)
0843       {
0844          return z2;
0845       }
0846 
0847    } while (max_iterations--);
0848 
0849    // The idea is that if we can get abs(f) < eps, we should, but if we go through all these iterations
0850    // and abs(f) < sqrt(eps), then roundoff error simply does not allow that we can evaluate f to < eps
0851    // This is somewhat awkward as it isn't scale invariant, but using the Daubechies coefficient example code,
0852    // I found this condition generates correct roots, whereas the scale invariant condition discussed here:
0853    // https://scicomp.stackexchange.com/questions/30597/defining-a-condition-number-and-termination-criteria-for-newtons-method
0854    // allows nonroots to be passed off as roots.
0855    auto pair = g(z2);
0856    if (abs(pair.first) < sqrt(std::numeric_limits<Real>::epsilon()))
0857    {
0858       return z2;
0859    }
0860 
0861    return { std::numeric_limits<Real>::quiet_NaN(),
0862             std::numeric_limits<Real>::quiet_NaN() };
0863 }
0864 #endif
0865 
0866 
0867 #if !defined(BOOST_NO_CXX17_IF_CONSTEXPR)
0868 // https://stackoverflow.com/questions/48979861/numerically-stable-method-for-solving-quadratic-equations/50065711
0869 namespace detail
0870 {
0871 #if defined(BOOST_GNU_STDLIB) && !defined(_GLIBCXX_USE_C99_MATH_TR1)
0872 inline float fma_workaround(float x, float y, float z) { return ::fmaf(x, y, z); }
0873 inline double fma_workaround(double x, double y, double z) { return ::fma(x, y, z); }
0874 #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
0875 inline long double fma_workaround(long double x, long double y, long double z) { return ::fmal(x, y, z); }
0876 #endif
0877 #endif            
0878 template<class T>
0879 inline T discriminant(T const& a, T const& b, T const& c)
0880 {
0881    T w = 4 * a * c;
0882 #if defined(BOOST_GNU_STDLIB) && !defined(_GLIBCXX_USE_C99_MATH_TR1)
0883    T e = fma_workaround(-c, 4 * a, w);
0884    T f = fma_workaround(b, b, -w);
0885 #else
0886    T e = std::fma(-c, 4 * a, w);
0887    T f = std::fma(b, b, -w);
0888 #endif
0889    return f + e;
0890 }
0891 
0892 template<class T>
0893 std::pair<T, T> quadratic_roots_imp(T const& a, T const& b, T const& c)
0894 {
0895 #if defined(BOOST_GNU_STDLIB) && !defined(_GLIBCXX_USE_C99_MATH_TR1)
0896    using boost::math::copysign;
0897 #else
0898    using std::copysign;
0899 #endif
0900    using std::sqrt;
0901    if constexpr (std::is_floating_point<T>::value)
0902    {
0903       T nan = std::numeric_limits<T>::quiet_NaN();
0904       if (a == 0)
0905       {
0906          if (b == 0 && c != 0)
0907          {
0908             return std::pair<T, T>(nan, nan);
0909          }
0910          else if (b == 0 && c == 0)
0911          {
0912             return std::pair<T, T>(0, 0);
0913          }
0914          return std::pair<T, T>(-c / b, -c / b);
0915       }
0916       if (b == 0)
0917       {
0918          T x0_sq = -c / a;
0919          if (x0_sq < 0) {
0920             return std::pair<T, T>(nan, nan);
0921          }
0922          T x0 = sqrt(x0_sq);
0923          return std::pair<T, T>(-x0, x0);
0924       }
0925       T discriminant = detail::discriminant(a, b, c);
0926       // Is there a sane way to flush very small negative values to zero?
0927       // If there is I don't know of it.
0928       if (discriminant < 0)
0929       {
0930          return std::pair<T, T>(nan, nan);
0931       }
0932       T q = -(b + copysign(sqrt(discriminant), b)) / T(2);
0933       T x0 = q / a;
0934       T x1 = c / q;
0935       if (x0 < x1)
0936       {
0937          return std::pair<T, T>(x0, x1);
0938       }
0939       return std::pair<T, T>(x1, x0);
0940    }
0941    else if constexpr (boost::math::tools::is_complex_type<T>::value)
0942    {
0943       typename T::value_type nan = std::numeric_limits<typename T::value_type>::quiet_NaN();
0944       if (a.real() == 0 && a.imag() == 0)
0945       {
0946          using std::norm;
0947          if (b.real() == 0 && b.imag() && norm(c) != 0)
0948          {
0949             return std::pair<T, T>({ nan, nan }, { nan, nan });
0950          }
0951          else if (b.real() == 0 && b.imag() && c.real() == 0 && c.imag() == 0)
0952          {
0953             return std::pair<T, T>({ 0,0 }, { 0,0 });
0954          }
0955          return std::pair<T, T>(-c / b, -c / b);
0956       }
0957       if (b.real() == 0 && b.imag() == 0)
0958       {
0959          T x0_sq = -c / a;
0960          T x0 = sqrt(x0_sq);
0961          return std::pair<T, T>(-x0, x0);
0962       }
0963       // There's no fma for complex types:
0964       T discriminant = b * b - T(4) * a * c;
0965       T q = -(b + sqrt(discriminant)) / T(2);
0966       return std::pair<T, T>(q / a, c / q);
0967    }
0968    else // Most likely the type is a boost.multiprecision.
0969    {    //There is no fma for multiprecision, and in addition it doesn't seem to be useful, so revert to the naive computation.
0970       T nan = std::numeric_limits<T>::quiet_NaN();
0971       if (a == 0)
0972       {
0973          if (b == 0 && c != 0)
0974          {
0975             return std::pair<T, T>(nan, nan);
0976          }
0977          else if (b == 0 && c == 0)
0978          {
0979             return std::pair<T, T>(0, 0);
0980          }
0981          return std::pair<T, T>(-c / b, -c / b);
0982       }
0983       if (b == 0)
0984       {
0985          T x0_sq = -c / a;
0986          if (x0_sq < 0) {
0987             return std::pair<T, T>(nan, nan);
0988          }
0989          T x0 = sqrt(x0_sq);
0990          return std::pair<T, T>(-x0, x0);
0991       }
0992       T discriminant = b * b - 4 * a * c;
0993       if (discriminant < 0)
0994       {
0995          return std::pair<T, T>(nan, nan);
0996       }
0997       T q = -(b + copysign(sqrt(discriminant), b)) / T(2);
0998       T x0 = q / a;
0999       T x1 = c / q;
1000       if (x0 < x1)
1001       {
1002          return std::pair<T, T>(x0, x1);
1003       }
1004       return std::pair<T, T>(x1, x0);
1005    }
1006 }
1007 }  // namespace detail
1008 
1009 template<class T1, class T2 = T1, class T3 = T1>
1010 inline std::pair<typename tools::promote_args<T1, T2, T3>::type, typename tools::promote_args<T1, T2, T3>::type> quadratic_roots(T1 const& a, T2 const& b, T3 const& c)
1011 {
1012    typedef typename tools::promote_args<T1, T2, T3>::type value_type;
1013    return detail::quadratic_roots_imp(static_cast<value_type>(a), static_cast<value_type>(b), static_cast<value_type>(c));
1014 }
1015 
1016 #endif
1017 
1018 } // namespace tools
1019 } // namespace math
1020 } // namespace boost
1021 
1022 #endif // BOOST_MATH_TOOLS_NEWTON_SOLVER_HPP