File indexing completed on 2025-09-15 08:40:42
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_MATH_TOOLS_NEWTON_SOLVER_HPP
0008 #define BOOST_MATH_TOOLS_NEWTON_SOLVER_HPP
0009
0010 #ifdef _MSC_VER
0011 #pragma once
0012 #endif
0013
0014 #include <boost/math/tools/config.hpp>
0015 #include <boost/math/tools/complex.hpp> // test for multiprecision types in complex Newton
0016 #include <boost/math/tools/type_traits.hpp>
0017 #include <boost/math/tools/cstdint.hpp>
0018 #include <boost/math/tools/numeric_limits.hpp>
0019 #include <boost/math/tools/tuple.hpp>
0020 #include <boost/math/special_functions/sign.hpp>
0021 #include <boost/math/policies/policy.hpp>
0022 #include <boost/math/policies/error_handling.hpp>
0023
0024 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
0025 #include <boost/math/special_functions/next.hpp>
0026 #include <boost/math/tools/toms748_solve.hpp>
0027 #endif
0028
0029 namespace boost {
0030 namespace math {
0031 namespace tools {
0032
0033 namespace detail {
0034
0035 namespace dummy {
0036
0037 template<int n, class T>
0038 BOOST_MATH_GPU_ENABLED typename T::value_type get(const T&) BOOST_MATH_NOEXCEPT(T);
0039 }
0040
0041 template <class Tuple, class T>
0042 BOOST_MATH_GPU_ENABLED void unpack_tuple(const Tuple& t, T& a, T& b) BOOST_MATH_NOEXCEPT(T)
0043 {
0044 using dummy::get;
0045
0046 a = get<0>(t);
0047 b = get<1>(t);
0048 }
0049 template <class Tuple, class T>
0050 BOOST_MATH_GPU_ENABLED void unpack_tuple(const Tuple& t, T& a, T& b, T& c) BOOST_MATH_NOEXCEPT(T)
0051 {
0052 using dummy::get;
0053
0054 a = get<0>(t);
0055 b = get<1>(t);
0056 c = get<2>(t);
0057 }
0058
0059 template <class Tuple, class T>
0060 BOOST_MATH_GPU_ENABLED inline void unpack_0(const Tuple& t, T& val) BOOST_MATH_NOEXCEPT(T)
0061 {
0062 using dummy::get;
0063
0064 val = get<0>(t);
0065 }
0066
0067 template <class T, class U, class V>
0068 BOOST_MATH_GPU_ENABLED inline void unpack_tuple(const boost::math::pair<T, U>& p, V& a, V& b) BOOST_MATH_NOEXCEPT(T)
0069 {
0070 a = p.first;
0071 b = p.second;
0072 }
0073 template <class T, class U, class V>
0074 BOOST_MATH_GPU_ENABLED inline void unpack_0(const boost::math::pair<T, U>& p, V& a) BOOST_MATH_NOEXCEPT(T)
0075 {
0076 a = p.first;
0077 }
0078
0079 template <class F, class T>
0080 BOOST_MATH_GPU_ENABLED void handle_zero_derivative(F f,
0081 T& last_f0,
0082 const T& f0,
0083 T& delta,
0084 T& result,
0085 T& guess,
0086 const T& min,
0087 const T& max) noexcept(BOOST_MATH_IS_FLOAT(T)
0088 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
0089 && noexcept(std::declval<F>()(std::declval<T>()))
0090 #endif
0091 )
0092 {
0093 if (last_f0 == 0)
0094 {
0095
0096
0097 if (result == min)
0098 {
0099 guess = max;
0100 }
0101 else
0102 {
0103 guess = min;
0104 }
0105 unpack_0(f(guess), last_f0);
0106 delta = guess - result;
0107 }
0108 if (sign(last_f0) * sign(f0) < 0)
0109 {
0110
0111 if (delta < 0)
0112 {
0113 delta = (result - min) / 2;
0114 }
0115 else
0116 {
0117 delta = (result - max) / 2;
0118 }
0119 }
0120 else
0121 {
0122
0123 if (delta < 0)
0124 {
0125 delta = (result - max) / 2;
0126 }
0127 else
0128 {
0129 delta = (result - min) / 2;
0130 }
0131 }
0132 }
0133
0134 }
0135
0136 template <class F, class T, class Tol, class Policy>
0137 BOOST_MATH_GPU_ENABLED boost::math::pair<T, T> bisect(F f, T min, T max, Tol tol, boost::math::uintmax_t& max_iter, const Policy& pol) noexcept(policies::is_noexcept_error_policy<Policy>::value && BOOST_MATH_IS_FLOAT(T)
0138 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
0139 && noexcept(std::declval<F>()(std::declval<T>()))
0140 #endif
0141 )
0142 {
0143 T fmin = f(min);
0144 T fmax = f(max);
0145 if (fmin == 0)
0146 {
0147 max_iter = 2;
0148 return boost::math::make_pair(min, min);
0149 }
0150 if (fmax == 0)
0151 {
0152 max_iter = 2;
0153 return boost::math::make_pair(max, max);
0154 }
0155
0156
0157
0158
0159 constexpr auto function = "boost::math::tools::bisect<%1%>";
0160 if (min >= max)
0161 {
0162 return boost::math::detail::pair_from_single(policies::raise_evaluation_error(function,
0163 "Arguments in wrong order in boost::math::tools::bisect (first arg=%1%)", min, pol));
0164 }
0165 if (fmin * fmax >= 0)
0166 {
0167 return boost::math::detail::pair_from_single(policies::raise_evaluation_error(function,
0168 "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));
0169 }
0170
0171
0172
0173
0174 std::uintmax_t count = max_iter;
0175 if (count < 3)
0176 count = 0;
0177 else
0178 count -= 3;
0179
0180 while (count && (0 == tol(min, max)))
0181 {
0182 T mid = (min + max) / 2;
0183 T fmid = f(mid);
0184 if ((mid == max) || (mid == min))
0185 break;
0186 if (fmid == 0)
0187 {
0188 min = max = mid;
0189 break;
0190 }
0191 else if (sign(fmid) * sign(fmin) < 0)
0192 {
0193 max = mid;
0194 }
0195 else
0196 {
0197 min = mid;
0198 fmin = fmid;
0199 }
0200 --count;
0201 }
0202
0203 max_iter -= count;
0204
0205 #ifdef BOOST_MATH_INSTRUMENT
0206 std::cout << "Bisection required " << max_iter << " iterations.\n";
0207 #endif
0208
0209 return boost::math::make_pair(min, max);
0210 }
0211
0212 template <class F, class T, class Tol>
0213 BOOST_MATH_GPU_ENABLED inline boost::math::pair<T, T> bisect(F f, T min, T max, Tol tol, boost::math::uintmax_t& max_iter) noexcept(policies::is_noexcept_error_policy<policies::policy<> >::value && BOOST_MATH_IS_FLOAT(T)
0214 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
0215 && noexcept(std::declval<F>()(std::declval<T>()))
0216 #endif
0217 )
0218 {
0219 return bisect(f, min, max, tol, max_iter, policies::policy<>());
0220 }
0221
0222 template <class F, class T, class Tol>
0223 BOOST_MATH_GPU_ENABLED inline boost::math::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)
0224 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
0225 && noexcept(std::declval<F>()(std::declval<T>()))
0226 #endif
0227 )
0228 {
0229 boost::math::uintmax_t m = (boost::math::numeric_limits<boost::math::uintmax_t>::max)();
0230 return bisect(f, min, max, tol, m, policies::policy<>());
0231 }
0232
0233
0234 template <class F, class T>
0235 BOOST_MATH_GPU_ENABLED T newton_raphson_iterate(F f, T guess, T min, T max, int digits, boost::math::uintmax_t& max_iter) noexcept(policies::is_noexcept_error_policy<policies::policy<> >::value && BOOST_MATH_IS_FLOAT(T)
0236 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
0237 && noexcept(std::declval<F>()(std::declval<T>()))
0238 #endif
0239 )
0240 {
0241 BOOST_MATH_STD_USING
0242
0243 constexpr auto function = "boost::math::tools::newton_raphson_iterate<%1%>";
0244 if (min > max)
0245 {
0246 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<>());
0247 }
0248
0249 T f0(0), f1, last_f0(0);
0250 T result = guess;
0251
0252 T factor = static_cast<T>(ldexp(1.0, 1 - digits));
0253 T delta = tools::max_value<T>();
0254 T delta1 = tools::max_value<T>();
0255 T delta2 = tools::max_value<T>();
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267 T max_range_f = 0;
0268 T min_range_f = 0;
0269
0270 boost::math::uintmax_t count(max_iter);
0271
0272 #ifdef BOOST_MATH_INSTRUMENT
0273 std::cout << "Newton_raphson_iterate, guess = " << guess << ", min = " << min << ", max = " << max
0274 << ", digits = " << digits << ", max_iter = " << max_iter << "\n";
0275 #endif
0276
0277 do {
0278 last_f0 = f0;
0279 delta2 = delta1;
0280 delta1 = delta;
0281 detail::unpack_tuple(f(result), f0, f1);
0282 --count;
0283 if (0 == f0)
0284 break;
0285 if (f1 == 0)
0286 {
0287
0288 detail::handle_zero_derivative(f, last_f0, f0, delta, result, guess, min, max);
0289 }
0290 else
0291 {
0292 delta = f0 / f1;
0293 }
0294 #ifdef BOOST_MATH_INSTRUMENT
0295 std::cout << "Newton iteration " << max_iter - count << ", delta = " << delta << ", residual = " << f0 << "\n";
0296 #endif
0297 if (fabs(delta * 2) > fabs(delta2))
0298 {
0299
0300 T shift = (delta > 0) ? (result - min) / 2 : (result - max) / 2;
0301 if ((result != 0) && (fabs(shift) > fabs(result)))
0302 {
0303 delta = sign(delta) * fabs(result);
0304 }
0305 else
0306 delta = shift;
0307
0308 delta1 = 3 * delta;
0309 delta2 = 3 * delta;
0310 }
0311 guess = result;
0312 result -= delta;
0313 if (result <= min)
0314 {
0315 delta = 0.5F * (guess - min);
0316 result = guess - delta;
0317 if ((result == min) || (result == max))
0318 break;
0319 }
0320 else if (result >= max)
0321 {
0322 delta = 0.5F * (guess - max);
0323 result = guess - delta;
0324 if ((result == min) || (result == max))
0325 break;
0326 }
0327
0328 if (delta > 0)
0329 {
0330 max = guess;
0331 max_range_f = f0;
0332 }
0333 else
0334 {
0335 min = guess;
0336 min_range_f = f0;
0337 }
0338
0339
0340
0341 if (max_range_f * min_range_f > 0)
0342 {
0343 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<>());
0344 }
0345 }while(count && (fabs(result * factor) < fabs(delta)));
0346
0347 max_iter -= count;
0348
0349 #ifdef BOOST_MATH_INSTRUMENT
0350 std::cout << "Newton Raphson required " << max_iter << " iterations\n";
0351 #endif
0352
0353 return result;
0354 }
0355
0356 template <class F, class T>
0357 BOOST_MATH_GPU_ENABLED 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)
0358 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
0359 && noexcept(std::declval<F>()(std::declval<T>()))
0360 #endif
0361 )
0362 {
0363 boost::math::uintmax_t m = (boost::math::numeric_limits<boost::math::uintmax_t>::max)();
0364 return newton_raphson_iterate(f, guess, min, max, digits, m);
0365 }
0366
0367
0368
0369 #ifdef BOOST_MATH_HAS_NVRTC
0370 }}}
0371 #else
0372
0373 namespace detail {
0374
0375 struct halley_step
0376 {
0377 template <class T>
0378 static T step(const T& , const T& f0, const T& f1, const T& f2) noexcept(BOOST_MATH_IS_FLOAT(T))
0379 {
0380 using std::fabs;
0381 T denom = 2 * f0;
0382 T num = 2 * f1 - f0 * (f2 / f1);
0383 T delta;
0384
0385 BOOST_MATH_INSTRUMENT_VARIABLE(denom);
0386 BOOST_MATH_INSTRUMENT_VARIABLE(num);
0387
0388 if ((fabs(num) < 1) && (fabs(denom) >= fabs(num) * tools::max_value<T>()))
0389 {
0390
0391 delta = f0 / f1;
0392 }
0393 else
0394 delta = denom / num;
0395 return delta;
0396 }
0397 };
0398
0399 template <class F, class T>
0400 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>())));
0401
0402 template <class F, class T>
0403 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>())))
0404 {
0405 using std::fabs;
0406 using std::ldexp;
0407 using std::abs;
0408 using std::frexp;
0409 if(count < 2)
0410 return guess - (max + min) / 2;
0411
0412
0413
0414 int e;
0415 frexp(max / guess, &e);
0416 e = abs(e);
0417 T guess0 = guess;
0418 T multiplier = e < 64 ? static_cast<T>(2) : static_cast<T>(ldexp(T(1), e / 32));
0419 T f_current = f0;
0420 if (fabs(min) < fabs(max))
0421 {
0422 while (--count && ((f_current < 0) == (f0 < 0)))
0423 {
0424 min = guess;
0425 guess *= multiplier;
0426 if (guess > max)
0427 {
0428 guess = max;
0429 f_current = -f_current;
0430 break;
0431 }
0432 multiplier *= e > 1024 ? 8 : 2;
0433 unpack_0(f(guess), f_current);
0434 }
0435 }
0436 else
0437 {
0438
0439
0440
0441 while (--count && ((f_current < 0) == (f0 < 0)))
0442 {
0443 min = guess;
0444 guess /= multiplier;
0445 if (guess > max)
0446 {
0447 guess = max;
0448 f_current = -f_current;
0449 break;
0450 }
0451 multiplier *= e > 1024 ? 8 : 2;
0452 unpack_0(f(guess), f_current);
0453 }
0454 }
0455
0456 if (count)
0457 {
0458 max = guess;
0459 if (multiplier > 16)
0460 return (guess0 - guess) + bracket_root_towards_min(f, guess, f_current, min, max, count);
0461 }
0462 return guess0 - (max + min) / 2;
0463 }
0464
0465 template <class F, class T>
0466 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>())))
0467 {
0468 using std::fabs;
0469 using std::ldexp;
0470 using std::abs;
0471 using std::frexp;
0472 if (count < 2)
0473 return guess - (max + min) / 2;
0474
0475
0476
0477 int e;
0478 frexp(guess / min, &e);
0479 e = abs(e);
0480 T guess0 = guess;
0481 T multiplier = e < 64 ? static_cast<T>(2) : static_cast<T>(ldexp(T(1), e / 32));
0482 T f_current = f0;
0483
0484 if (fabs(min) < fabs(max))
0485 {
0486 while (--count && ((f_current < 0) == (f0 < 0)))
0487 {
0488 max = guess;
0489 guess /= multiplier;
0490 if (guess < min)
0491 {
0492 guess = min;
0493 f_current = -f_current;
0494 break;
0495 }
0496 multiplier *= e > 1024 ? 8 : 2;
0497 unpack_0(f(guess), f_current);
0498 }
0499 }
0500 else
0501 {
0502
0503
0504
0505 while (--count && ((f_current < 0) == (f0 < 0)))
0506 {
0507 max = guess;
0508 guess *= multiplier;
0509 if (guess < min)
0510 {
0511 guess = min;
0512 f_current = -f_current;
0513 break;
0514 }
0515 multiplier *= e > 1024 ? 8 : 2;
0516 unpack_0(f(guess), f_current);
0517 }
0518 }
0519
0520 if (count)
0521 {
0522 min = guess;
0523 if (multiplier > 16)
0524 return (guess0 - guess) + bracket_root_towards_max(f, guess, f_current, min, max, count);
0525 }
0526 return guess0 - (max + min) / 2;
0527 }
0528
0529 template <class Stepper, class F, class T>
0530 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>())))
0531 {
0532 BOOST_MATH_STD_USING
0533
0534 #ifdef BOOST_MATH_INSTRUMENT
0535 std::cout << "Second order root iteration, guess = " << guess << ", min = " << min << ", max = " << max
0536 << ", digits = " << digits << ", max_iter = " << max_iter << "\n";
0537 #endif
0538 static const char* function = "boost::math::tools::halley_iterate<%1%>";
0539 if (min >= max)
0540 {
0541 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<>());
0542 }
0543
0544 T f0(0), f1, f2;
0545 T result = guess;
0546
0547 T factor = ldexp(static_cast<T>(1.0), 1 - digits);
0548 T delta = (std::max)(T(10000000 * guess), T(10000000));
0549 T last_f0 = 0;
0550 T delta1 = delta;
0551 T delta2 = delta;
0552 bool out_of_bounds_sentry = false;
0553
0554 #ifdef BOOST_MATH_INSTRUMENT
0555 std::cout << "Second order root iteration, limit = " << factor << "\n";
0556 #endif
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568 T max_range_f = 0;
0569 T min_range_f = 0;
0570
0571 std::uintmax_t count(max_iter);
0572
0573 do {
0574 last_f0 = f0;
0575 delta2 = delta1;
0576 delta1 = delta;
0577 #ifndef BOOST_MATH_NO_EXCEPTIONS
0578 try
0579 #endif
0580 {
0581 detail::unpack_tuple(f(result), f0, f1, f2);
0582 }
0583 #ifndef BOOST_MATH_NO_EXCEPTIONS
0584 catch (const std::overflow_error&)
0585 {
0586 f0 = max > 0 ? tools::max_value<T>() : -tools::min_value<T>();
0587 f1 = f2 = 0;
0588 }
0589 #endif
0590 --count;
0591
0592 BOOST_MATH_INSTRUMENT_VARIABLE(f0);
0593 BOOST_MATH_INSTRUMENT_VARIABLE(f1);
0594 BOOST_MATH_INSTRUMENT_VARIABLE(f2);
0595
0596 if (0 == f0)
0597 break;
0598 if (f1 == 0)
0599 {
0600
0601 detail::handle_zero_derivative(f, last_f0, f0, delta, result, guess, min, max);
0602 }
0603 else
0604 {
0605 if (f2 != 0)
0606 {
0607 delta = Stepper::step(result, f0, f1, f2);
0608 if (delta * f1 / f0 < 0)
0609 {
0610
0611
0612
0613
0614
0615
0616
0617
0618
0619 delta = f0 / f1;
0620 if (fabs(delta) > 2 * fabs(result))
0621 delta = (delta < 0 ? -1 : 1) * 2 * fabs(result);
0622 }
0623 }
0624 else
0625 delta = f0 / f1;
0626 }
0627 #ifdef BOOST_MATH_INSTRUMENT
0628 std::cout << "Second order root iteration, delta = " << delta << ", residual = " << f0 << "\n";
0629 #endif
0630
0631 T convergence = (fabs(delta2) > 1) || (fabs(tools::max_value<T>() * delta2) > fabs(delta)) ? fabs(delta / delta2) : tools::max_value<T>();
0632 if ((convergence > 0.8) && (convergence < 2))
0633 {
0634
0635 if (fabs(min) < 1 ? fabs(1000 * min) < fabs(max) : fabs(max / min) > 1000)
0636 {
0637 if(delta > 0)
0638 delta = bracket_root_towards_min(f, result, f0, min, max, count);
0639 else
0640 delta = bracket_root_towards_max(f, result, f0, min, max, count);
0641 }
0642 else
0643 {
0644 delta = (delta > 0) ? (result - min) / 2 : (result - max) / 2;
0645 if ((result != 0) && (fabs(delta) > result))
0646 delta = sign(delta) * fabs(result) * 0.9f;
0647 }
0648
0649
0650 delta2 = delta * 3;
0651 delta1 = delta * 3;
0652 BOOST_MATH_INSTRUMENT_VARIABLE(delta);
0653 }
0654 guess = result;
0655 result -= delta;
0656 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0657
0658
0659 if (result < min)
0660 {
0661 T diff = ((fabs(min) < 1) && (fabs(result) > 1) && (tools::max_value<T>() / fabs(result) < fabs(min)))
0662 ? T(1000)
0663 : (fabs(min) < 1) && (fabs(tools::max_value<T>() * min) < fabs(result))
0664 ? ((min < 0) != (result < 0)) ? -tools::max_value<T>() : tools::max_value<T>() : T(result / min);
0665 if (fabs(diff) < 1)
0666 diff = 1 / diff;
0667 if (!out_of_bounds_sentry && (diff > 0) && (diff < 3))
0668 {
0669
0670
0671 delta = 0.99f * (guess - min);
0672 result = guess - delta;
0673 out_of_bounds_sentry = true;
0674 }
0675 else
0676 {
0677 if (fabs(float_distance(min, max)) < 2)
0678 {
0679 result = guess = (min + max) / 2;
0680 break;
0681 }
0682 delta = bracket_root_towards_min(f, guess, f0, min, max, count);
0683 result = guess - delta;
0684 if (result <= min)
0685 result = float_next(min);
0686 if (result >= max)
0687 result = float_prior(max);
0688 guess = min;
0689 continue;
0690 }
0691 }
0692 else if (result > max)
0693 {
0694 T diff = ((fabs(max) < 1) && (fabs(result) > 1) && (tools::max_value<T>() / fabs(result) < fabs(max))) ? T(1000) : T(result / max);
0695 if (fabs(diff) < 1)
0696 diff = 1 / diff;
0697 if (!out_of_bounds_sentry && (diff > 0) && (diff < 3))
0698 {
0699
0700
0701 delta = 0.99f * (guess - max);
0702 result = guess - delta;
0703 out_of_bounds_sentry = true;
0704 }
0705 else
0706 {
0707 if (fabs(float_distance(min, max)) < 2)
0708 {
0709 result = guess = (min + max) / 2;
0710 break;
0711 }
0712 delta = bracket_root_towards_max(f, guess, f0, min, max, count);
0713 result = guess - delta;
0714 if (result >= max)
0715 result = float_prior(max);
0716 if (result <= min)
0717 result = float_next(min);
0718 guess = min;
0719 continue;
0720 }
0721 }
0722
0723 if (delta > 0)
0724 {
0725 max = guess;
0726 max_range_f = f0;
0727 }
0728 else
0729 {
0730 min = guess;
0731 min_range_f = f0;
0732 }
0733
0734
0735
0736 if (max_range_f * min_range_f > 0)
0737 {
0738 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<>());
0739 }
0740 } while(count && (fabs(result * factor) < fabs(delta)));
0741
0742 max_iter -= count;
0743
0744 #ifdef BOOST_MATH_INSTRUMENT
0745 std::cout << "Second order root finder required " << max_iter << " iterations.\n";
0746 #endif
0747
0748 return result;
0749 }
0750 }
0751
0752 template <class F, class T>
0753 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>())))
0754 {
0755 return detail::second_order_root_finder<detail::halley_step>(f, guess, min, max, digits, max_iter);
0756 }
0757
0758 template <class F, class T>
0759 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>())))
0760 {
0761 std::uintmax_t m = (std::numeric_limits<std::uintmax_t>::max)();
0762 return halley_iterate(f, guess, min, max, digits, m);
0763 }
0764
0765 namespace detail {
0766
0767 struct schroder_stepper
0768 {
0769 template <class T>
0770 static T step(const T& x, const T& f0, const T& f1, const T& f2) noexcept(BOOST_MATH_IS_FLOAT(T))
0771 {
0772 using std::fabs;
0773 T ratio = f0 / f1;
0774 T delta;
0775 if ((x != 0) && (fabs(ratio / x) < 0.1))
0776 {
0777 delta = ratio + (f2 / (2 * f1)) * ratio * ratio;
0778
0779 if (delta * ratio < 0)
0780 delta = ratio;
0781 }
0782 else
0783 delta = ratio;
0784 return delta;
0785 }
0786 };
0787
0788 }
0789
0790 template <class F, class T>
0791 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>())))
0792 {
0793 return detail::second_order_root_finder<detail::schroder_stepper>(f, guess, min, max, digits, max_iter);
0794 }
0795
0796 template <class F, class T>
0797 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>())))
0798 {
0799 std::uintmax_t m = (std::numeric_limits<std::uintmax_t>::max)();
0800 return schroder_iterate(f, guess, min, max, digits, m);
0801 }
0802
0803
0804
0805 template <class F, class T>
0806 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>())))
0807 {
0808 return detail::second_order_root_finder<detail::schroder_stepper>(f, guess, min, max, digits, max_iter);
0809 }
0810
0811 template <class F, class T>
0812 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>())))
0813 {
0814 std::uintmax_t m = (std::numeric_limits<std::uintmax_t>::max)();
0815 return schroder_iterate(f, guess, min, max, digits, m);
0816 }
0817
0818 #ifndef BOOST_NO_CXX11_AUTO_DECLARATIONS
0819
0820
0821
0822
0823
0824
0825 template<class ComplexType, class F>
0826 ComplexType complex_newton(F g, ComplexType guess, int max_iterations = std::numeric_limits<typename ComplexType::value_type>::digits)
0827 {
0828 typedef typename ComplexType::value_type Real;
0829 using std::norm;
0830 using std::abs;
0831 using std::max;
0832
0833 ComplexType z0 = guess + ComplexType(1, 0);
0834 ComplexType z1 = guess + ComplexType(0, 1);
0835 ComplexType z2 = guess;
0836
0837 do {
0838 auto pair = g(z2);
0839 if (norm(pair.second) == 0)
0840 {
0841
0842 ComplexType q = (z2 - z1) / (z1 - z0);
0843 auto P0 = g(z0);
0844 auto P1 = g(z1);
0845 ComplexType qp1 = static_cast<ComplexType>(1) + q;
0846 ComplexType A = q * (pair.first - qp1 * P1.first + q * P0.first);
0847
0848 ComplexType B = (static_cast<ComplexType>(2) * q + static_cast<ComplexType>(1)) * pair.first - qp1 * qp1 * P1.first + q * q * P0.first;
0849 ComplexType C = qp1 * pair.first;
0850 ComplexType rad = sqrt(B * B - static_cast<ComplexType>(4) * A * C);
0851 ComplexType denom1 = B + rad;
0852 ComplexType denom2 = B - rad;
0853 ComplexType correction = (z1 - z2) * static_cast<ComplexType>(2) * C;
0854 if (norm(denom1) > norm(denom2))
0855 {
0856 correction /= denom1;
0857 }
0858 else
0859 {
0860 correction /= denom2;
0861 }
0862
0863 z0 = z1;
0864 z1 = z2;
0865 z2 = z2 + correction;
0866 }
0867 else
0868 {
0869 z0 = z1;
0870 z1 = z2;
0871 z2 = z2 - (pair.first / pair.second);
0872 }
0873
0874
0875
0876
0877 Real tol = (max)(abs(z2) * std::numeric_limits<Real>::epsilon(), std::numeric_limits<Real>::epsilon());
0878 bool real_close = abs(z0.real() - z1.real()) < tol && abs(z0.real() - z2.real()) < tol && abs(z1.real() - z2.real()) < tol;
0879 bool imag_close = abs(z0.imag() - z1.imag()) < tol && abs(z0.imag() - z2.imag()) < tol && abs(z1.imag() - z2.imag()) < tol;
0880 if (real_close && imag_close)
0881 {
0882 return z2;
0883 }
0884
0885 } while (max_iterations--);
0886
0887
0888
0889
0890
0891
0892
0893 auto pair = g(z2);
0894 if (abs(pair.first) < sqrt(std::numeric_limits<Real>::epsilon()))
0895 {
0896 return z2;
0897 }
0898
0899 return { std::numeric_limits<Real>::quiet_NaN(),
0900 std::numeric_limits<Real>::quiet_NaN() };
0901 }
0902 #endif
0903
0904
0905 #if !defined(BOOST_MATH_NO_CXX17_IF_CONSTEXPR)
0906
0907 namespace detail
0908 {
0909 #if defined(BOOST_GNU_STDLIB) && !defined(_GLIBCXX_USE_C99_MATH_TR1)
0910 inline float fma_workaround(float x, float y, float z) { return ::fmaf(x, y, z); }
0911 inline double fma_workaround(double x, double y, double z) { return ::fma(x, y, z); }
0912 #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
0913 inline long double fma_workaround(long double x, long double y, long double z) { return ::fmal(x, y, z); }
0914 #endif
0915 #endif
0916 template<class T>
0917 inline T discriminant(T const& a, T const& b, T const& c)
0918 {
0919 T w = 4 * a * c;
0920 #if defined(BOOST_GNU_STDLIB) && !defined(_GLIBCXX_USE_C99_MATH_TR1)
0921 T e = fma_workaround(-c, 4 * a, w);
0922 T f = fma_workaround(b, b, -w);
0923 #else
0924 T e = std::fma(-c, 4 * a, w);
0925 T f = std::fma(b, b, -w);
0926 #endif
0927 return f + e;
0928 }
0929
0930 template<class T>
0931 std::pair<T, T> quadratic_roots_imp(T const& a, T const& b, T const& c)
0932 {
0933 #if defined(BOOST_GNU_STDLIB) && !defined(_GLIBCXX_USE_C99_MATH_TR1)
0934 using boost::math::copysign;
0935 #else
0936 using std::copysign;
0937 #endif
0938 using std::sqrt;
0939 if constexpr (std::is_floating_point<T>::value)
0940 {
0941 T nan = std::numeric_limits<T>::quiet_NaN();
0942 if (a == 0)
0943 {
0944 if (b == 0 && c != 0)
0945 {
0946 return std::pair<T, T>(nan, nan);
0947 }
0948 else if (b == 0 && c == 0)
0949 {
0950 return std::pair<T, T>(0, 0);
0951 }
0952 return std::pair<T, T>(-c / b, -c / b);
0953 }
0954 if (b == 0)
0955 {
0956 T x0_sq = -c / a;
0957 if (x0_sq < 0) {
0958 return std::pair<T, T>(nan, nan);
0959 }
0960 T x0 = sqrt(x0_sq);
0961 return std::pair<T, T>(-x0, x0);
0962 }
0963 T discriminant = detail::discriminant(a, b, c);
0964
0965
0966 if (discriminant < 0)
0967 {
0968 return std::pair<T, T>(nan, nan);
0969 }
0970 T q = -(b + copysign(sqrt(discriminant), b)) / T(2);
0971 T x0 = q / a;
0972 T x1 = c / q;
0973 if (x0 < x1)
0974 {
0975 return std::pair<T, T>(x0, x1);
0976 }
0977 return std::pair<T, T>(x1, x0);
0978 }
0979 else if constexpr (boost::math::tools::is_complex_type<T>::value)
0980 {
0981 typename T::value_type nan = std::numeric_limits<typename T::value_type>::quiet_NaN();
0982 if (a.real() == 0 && a.imag() == 0)
0983 {
0984 using std::norm;
0985 if (b.real() == 0 && b.imag() && norm(c) != 0)
0986 {
0987 return std::pair<T, T>({ nan, nan }, { nan, nan });
0988 }
0989 else if (b.real() == 0 && b.imag() && c.real() == 0 && c.imag() == 0)
0990 {
0991 return std::pair<T, T>({ 0,0 }, { 0,0 });
0992 }
0993 return std::pair<T, T>(-c / b, -c / b);
0994 }
0995 if (b.real() == 0 && b.imag() == 0)
0996 {
0997 T x0_sq = -c / a;
0998 T x0 = sqrt(x0_sq);
0999 return std::pair<T, T>(-x0, x0);
1000 }
1001
1002 T discriminant = b * b - T(4) * a * c;
1003 T q = -(b + sqrt(discriminant)) / T(2);
1004 return std::pair<T, T>(q / a, c / q);
1005 }
1006 else
1007 {
1008 T nan = std::numeric_limits<T>::quiet_NaN();
1009 if (a == 0)
1010 {
1011 if (b == 0 && c != 0)
1012 {
1013 return std::pair<T, T>(nan, nan);
1014 }
1015 else if (b == 0 && c == 0)
1016 {
1017 return std::pair<T, T>(0, 0);
1018 }
1019 return std::pair<T, T>(-c / b, -c / b);
1020 }
1021 if (b == 0)
1022 {
1023 T x0_sq = -c / a;
1024 if (x0_sq < 0) {
1025 return std::pair<T, T>(nan, nan);
1026 }
1027 T x0 = sqrt(x0_sq);
1028 return std::pair<T, T>(-x0, x0);
1029 }
1030 T discriminant = b * b - 4 * a * c;
1031 if (discriminant < 0)
1032 {
1033 return std::pair<T, T>(nan, nan);
1034 }
1035 T q = -(b + copysign(sqrt(discriminant), b)) / T(2);
1036 T x0 = q / a;
1037 T x1 = c / q;
1038 if (x0 < x1)
1039 {
1040 return std::pair<T, T>(x0, x1);
1041 }
1042 return std::pair<T, T>(x1, x0);
1043 }
1044 }
1045 }
1046
1047 template<class T1, class T2 = T1, class T3 = T1>
1048 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)
1049 {
1050 typedef typename tools::promote_args<T1, T2, T3>::type value_type;
1051 return detail::quadratic_roots_imp(static_cast<value_type>(a), static_cast<value_type>(b), static_cast<value_type>(c));
1052 }
1053
1054 #endif
1055
1056 }
1057 }
1058 }
1059
1060 #endif
1061
1062 #endif