File indexing completed on 2025-06-30 08:19:23
0001
0002
0003
0004
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
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
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
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
0090
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
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
0117 if (delta < 0)
0118 {
0119 delta = (result - max) / 2;
0120 }
0121 else
0122 {
0123 delta = (result - min) / 2;
0124 }
0125 }
0126 }
0127
0128 }
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
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
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
0237
0238
0239
0240
0241
0242
0243
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
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
0278 T shift = (delta > 0) ? (result - min) / 2 : (result - max) / 2;
0279 if ((result != 0) && (fabs(shift) > fabs(result)))
0280 {
0281 delta = sign(delta) * fabs(result);
0282 }
0283 else
0284 delta = shift;
0285
0286 delta1 = 3 * delta;
0287 delta2 = 3 * delta;
0288 }
0289 guess = result;
0290 result -= delta;
0291 if (result <= min)
0292 {
0293 delta = 0.5F * (guess - min);
0294 result = guess - delta;
0295 if ((result == min) || (result == max))
0296 break;
0297 }
0298 else if (result >= max)
0299 {
0300 delta = 0.5F * (guess - max);
0301 result = guess - delta;
0302 if ((result == min) || (result == max))
0303 break;
0304 }
0305
0306 if (delta > 0)
0307 {
0308 max = guess;
0309 max_range_f = f0;
0310 }
0311 else
0312 {
0313 min = guess;
0314 min_range_f = f0;
0315 }
0316
0317
0318
0319 if (max_range_f * min_range_f > 0)
0320 {
0321 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<>());
0322 }
0323 }while(count && (fabs(result * factor) < fabs(delta)));
0324
0325 max_iter -= count;
0326
0327 #ifdef BOOST_MATH_INSTRUMENT
0328 std::cout << "Newton Raphson required " << max_iter << " iterations\n";
0329 #endif
0330
0331 return result;
0332 }
0333
0334 template <class F, class T>
0335 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>())))
0336 {
0337 std::uintmax_t m = (std::numeric_limits<std::uintmax_t>::max)();
0338 return newton_raphson_iterate(f, guess, min, max, digits, m);
0339 }
0340
0341 namespace detail {
0342
0343 struct halley_step
0344 {
0345 template <class T>
0346 static T step(const T& , const T& f0, const T& f1, const T& f2) noexcept(BOOST_MATH_IS_FLOAT(T))
0347 {
0348 using std::fabs;
0349 T denom = 2 * f0;
0350 T num = 2 * f1 - f0 * (f2 / f1);
0351 T delta;
0352
0353 BOOST_MATH_INSTRUMENT_VARIABLE(denom);
0354 BOOST_MATH_INSTRUMENT_VARIABLE(num);
0355
0356 if ((fabs(num) < 1) && (fabs(denom) >= fabs(num) * tools::max_value<T>()))
0357 {
0358
0359 delta = f0 / f1;
0360 }
0361 else
0362 delta = denom / num;
0363 return delta;
0364 }
0365 };
0366
0367 template <class F, class T>
0368 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>())));
0369
0370 template <class F, class T>
0371 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>())))
0372 {
0373 using std::fabs;
0374 using std::ldexp;
0375 using std::abs;
0376 using std::frexp;
0377 if(count < 2)
0378 return guess - (max + min) / 2;
0379
0380
0381
0382 int e;
0383 frexp(max / guess, &e);
0384 e = abs(e);
0385 T guess0 = guess;
0386 T multiplier = e < 64 ? static_cast<T>(2) : static_cast<T>(ldexp(T(1), e / 32));
0387 T f_current = f0;
0388 if (fabs(min) < fabs(max))
0389 {
0390 while (--count && ((f_current < 0) == (f0 < 0)))
0391 {
0392 min = guess;
0393 guess *= multiplier;
0394 if (guess > max)
0395 {
0396 guess = max;
0397 f_current = -f_current;
0398 break;
0399 }
0400 multiplier *= e > 1024 ? 8 : 2;
0401 unpack_0(f(guess), f_current);
0402 }
0403 }
0404 else
0405 {
0406
0407
0408
0409 while (--count && ((f_current < 0) == (f0 < 0)))
0410 {
0411 min = guess;
0412 guess /= multiplier;
0413 if (guess > max)
0414 {
0415 guess = max;
0416 f_current = -f_current;
0417 break;
0418 }
0419 multiplier *= e > 1024 ? 8 : 2;
0420 unpack_0(f(guess), f_current);
0421 }
0422 }
0423
0424 if (count)
0425 {
0426 max = guess;
0427 if (multiplier > 16)
0428 return (guess0 - guess) + bracket_root_towards_min(f, guess, f_current, min, max, count);
0429 }
0430 return guess0 - (max + min) / 2;
0431 }
0432
0433 template <class F, class T>
0434 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>())))
0435 {
0436 using std::fabs;
0437 using std::ldexp;
0438 using std::abs;
0439 using std::frexp;
0440 if (count < 2)
0441 return guess - (max + min) / 2;
0442
0443
0444
0445 int e;
0446 frexp(guess / min, &e);
0447 e = abs(e);
0448 T guess0 = guess;
0449 T multiplier = e < 64 ? static_cast<T>(2) : static_cast<T>(ldexp(T(1), e / 32));
0450 T f_current = f0;
0451
0452 if (fabs(min) < fabs(max))
0453 {
0454 while (--count && ((f_current < 0) == (f0 < 0)))
0455 {
0456 max = guess;
0457 guess /= multiplier;
0458 if (guess < min)
0459 {
0460 guess = min;
0461 f_current = -f_current;
0462 break;
0463 }
0464 multiplier *= e > 1024 ? 8 : 2;
0465 unpack_0(f(guess), f_current);
0466 }
0467 }
0468 else
0469 {
0470
0471
0472
0473 while (--count && ((f_current < 0) == (f0 < 0)))
0474 {
0475 max = guess;
0476 guess *= multiplier;
0477 if (guess < min)
0478 {
0479 guess = min;
0480 f_current = -f_current;
0481 break;
0482 }
0483 multiplier *= e > 1024 ? 8 : 2;
0484 unpack_0(f(guess), f_current);
0485 }
0486 }
0487
0488 if (count)
0489 {
0490 min = guess;
0491 if (multiplier > 16)
0492 return (guess0 - guess) + bracket_root_towards_max(f, guess, f_current, min, max, count);
0493 }
0494 return guess0 - (max + min) / 2;
0495 }
0496
0497 template <class Stepper, class F, class T>
0498 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>())))
0499 {
0500 BOOST_MATH_STD_USING
0501
0502 #ifdef BOOST_MATH_INSTRUMENT
0503 std::cout << "Second order root iteration, guess = " << guess << ", min = " << min << ", max = " << max
0504 << ", digits = " << digits << ", max_iter = " << max_iter << "\n";
0505 #endif
0506 static const char* function = "boost::math::tools::halley_iterate<%1%>";
0507 if (min >= max)
0508 {
0509 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<>());
0510 }
0511
0512 T f0(0), f1, f2;
0513 T result = guess;
0514
0515 T factor = ldexp(static_cast<T>(1.0), 1 - digits);
0516 T delta = (std::max)(T(10000000 * guess), T(10000000));
0517 T last_f0 = 0;
0518 T delta1 = delta;
0519 T delta2 = delta;
0520 bool out_of_bounds_sentry = false;
0521
0522 #ifdef BOOST_MATH_INSTRUMENT
0523 std::cout << "Second order root iteration, limit = " << factor << "\n";
0524 #endif
0525
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536 T max_range_f = 0;
0537 T min_range_f = 0;
0538
0539 std::uintmax_t count(max_iter);
0540
0541 do {
0542 last_f0 = f0;
0543 delta2 = delta1;
0544 delta1 = delta;
0545 #ifndef BOOST_MATH_NO_EXCEPTIONS
0546 try
0547 #endif
0548 {
0549 detail::unpack_tuple(f(result), f0, f1, f2);
0550 }
0551 #ifndef BOOST_MATH_NO_EXCEPTIONS
0552 catch (const std::overflow_error&)
0553 {
0554 f0 = max > 0 ? tools::max_value<T>() : -tools::min_value<T>();
0555 f1 = f2 = 0;
0556 }
0557 #endif
0558 --count;
0559
0560 BOOST_MATH_INSTRUMENT_VARIABLE(f0);
0561 BOOST_MATH_INSTRUMENT_VARIABLE(f1);
0562 BOOST_MATH_INSTRUMENT_VARIABLE(f2);
0563
0564 if (0 == f0)
0565 break;
0566 if (f1 == 0)
0567 {
0568
0569 detail::handle_zero_derivative(f, last_f0, f0, delta, result, guess, min, max);
0570 }
0571 else
0572 {
0573 if (f2 != 0)
0574 {
0575 delta = Stepper::step(result, f0, f1, f2);
0576 if (delta * f1 / f0 < 0)
0577 {
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587 delta = f0 / f1;
0588 if (fabs(delta) > 2 * fabs(result))
0589 delta = (delta < 0 ? -1 : 1) * 2 * fabs(result);
0590 }
0591 }
0592 else
0593 delta = f0 / f1;
0594 }
0595 #ifdef BOOST_MATH_INSTRUMENT
0596 std::cout << "Second order root iteration, delta = " << delta << ", residual = " << f0 << "\n";
0597 #endif
0598
0599 T convergence = (fabs(delta2) > 1) || (fabs(tools::max_value<T>() * delta2) > fabs(delta)) ? fabs(delta / delta2) : tools::max_value<T>();
0600 if ((convergence > 0.8) && (convergence < 2))
0601 {
0602
0603 if (fabs(min) < 1 ? fabs(1000 * min) < fabs(max) : fabs(max / min) > 1000)
0604 {
0605 if(delta > 0)
0606 delta = bracket_root_towards_min(f, result, f0, min, max, count);
0607 else
0608 delta = bracket_root_towards_max(f, result, f0, min, max, count);
0609 }
0610 else
0611 {
0612 delta = (delta > 0) ? (result - min) / 2 : (result - max) / 2;
0613 if ((result != 0) && (fabs(delta) > result))
0614 delta = sign(delta) * fabs(result) * 0.9f;
0615 }
0616
0617
0618 delta2 = delta * 3;
0619 delta1 = delta * 3;
0620 BOOST_MATH_INSTRUMENT_VARIABLE(delta);
0621 }
0622 guess = result;
0623 result -= delta;
0624 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0625
0626
0627 if (result < min)
0628 {
0629 T diff = ((fabs(min) < 1) && (fabs(result) > 1) && (tools::max_value<T>() / fabs(result) < fabs(min)))
0630 ? T(1000)
0631 : (fabs(min) < 1) && (fabs(tools::max_value<T>() * min) < fabs(result))
0632 ? ((min < 0) != (result < 0)) ? -tools::max_value<T>() : tools::max_value<T>() : T(result / min);
0633 if (fabs(diff) < 1)
0634 diff = 1 / diff;
0635 if (!out_of_bounds_sentry && (diff > 0) && (diff < 3))
0636 {
0637
0638
0639 delta = 0.99f * (guess - min);
0640 result = guess - delta;
0641 out_of_bounds_sentry = true;
0642 }
0643 else
0644 {
0645 if (fabs(float_distance(min, max)) < 2)
0646 {
0647 result = guess = (min + max) / 2;
0648 break;
0649 }
0650 delta = bracket_root_towards_min(f, guess, f0, min, max, count);
0651 result = guess - delta;
0652 if (result <= min)
0653 result = float_next(min);
0654 if (result >= max)
0655 result = float_prior(max);
0656 guess = min;
0657 continue;
0658 }
0659 }
0660 else if (result > max)
0661 {
0662 T diff = ((fabs(max) < 1) && (fabs(result) > 1) && (tools::max_value<T>() / fabs(result) < fabs(max))) ? T(1000) : T(result / max);
0663 if (fabs(diff) < 1)
0664 diff = 1 / diff;
0665 if (!out_of_bounds_sentry && (diff > 0) && (diff < 3))
0666 {
0667
0668
0669 delta = 0.99f * (guess - max);
0670 result = guess - delta;
0671 out_of_bounds_sentry = true;
0672 }
0673 else
0674 {
0675 if (fabs(float_distance(min, max)) < 2)
0676 {
0677 result = guess = (min + max) / 2;
0678 break;
0679 }
0680 delta = bracket_root_towards_max(f, guess, f0, min, max, count);
0681 result = guess - delta;
0682 if (result >= max)
0683 result = float_prior(max);
0684 if (result <= min)
0685 result = float_next(min);
0686 guess = min;
0687 continue;
0688 }
0689 }
0690
0691 if (delta > 0)
0692 {
0693 max = guess;
0694 max_range_f = f0;
0695 }
0696 else
0697 {
0698 min = guess;
0699 min_range_f = f0;
0700 }
0701
0702
0703
0704 if (max_range_f * min_range_f > 0)
0705 {
0706 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<>());
0707 }
0708 } while(count && (fabs(result * factor) < fabs(delta)));
0709
0710 max_iter -= count;
0711
0712 #ifdef BOOST_MATH_INSTRUMENT
0713 std::cout << "Second order root finder required " << max_iter << " iterations.\n";
0714 #endif
0715
0716 return result;
0717 }
0718 }
0719
0720 template <class F, class T>
0721 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>())))
0722 {
0723 return detail::second_order_root_finder<detail::halley_step>(f, guess, min, max, digits, max_iter);
0724 }
0725
0726 template <class F, class T>
0727 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>())))
0728 {
0729 std::uintmax_t m = (std::numeric_limits<std::uintmax_t>::max)();
0730 return halley_iterate(f, guess, min, max, digits, m);
0731 }
0732
0733 namespace detail {
0734
0735 struct schroder_stepper
0736 {
0737 template <class T>
0738 static T step(const T& x, const T& f0, const T& f1, const T& f2) noexcept(BOOST_MATH_IS_FLOAT(T))
0739 {
0740 using std::fabs;
0741 T ratio = f0 / f1;
0742 T delta;
0743 if ((x != 0) && (fabs(ratio / x) < 0.1))
0744 {
0745 delta = ratio + (f2 / (2 * f1)) * ratio * ratio;
0746
0747 if (delta * ratio < 0)
0748 delta = ratio;
0749 }
0750 else
0751 delta = ratio;
0752 return delta;
0753 }
0754 };
0755
0756 }
0757
0758 template <class F, class T>
0759 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>())))
0760 {
0761 return detail::second_order_root_finder<detail::schroder_stepper>(f, guess, min, max, digits, max_iter);
0762 }
0763
0764 template <class F, class T>
0765 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>())))
0766 {
0767 std::uintmax_t m = (std::numeric_limits<std::uintmax_t>::max)();
0768 return schroder_iterate(f, guess, min, max, digits, m);
0769 }
0770
0771
0772
0773 template <class F, class T>
0774 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>())))
0775 {
0776 return detail::second_order_root_finder<detail::schroder_stepper>(f, guess, min, max, digits, max_iter);
0777 }
0778
0779 template <class F, class T>
0780 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>())))
0781 {
0782 std::uintmax_t m = (std::numeric_limits<std::uintmax_t>::max)();
0783 return schroder_iterate(f, guess, min, max, digits, m);
0784 }
0785
0786 #ifndef BOOST_NO_CXX11_AUTO_DECLARATIONS
0787
0788
0789
0790
0791
0792
0793 template<class ComplexType, class F>
0794 ComplexType complex_newton(F g, ComplexType guess, int max_iterations = std::numeric_limits<typename ComplexType::value_type>::digits)
0795 {
0796 typedef typename ComplexType::value_type Real;
0797 using std::norm;
0798 using std::abs;
0799 using std::max;
0800
0801 ComplexType z0 = guess + ComplexType(1, 0);
0802 ComplexType z1 = guess + ComplexType(0, 1);
0803 ComplexType z2 = guess;
0804
0805 do {
0806 auto pair = g(z2);
0807 if (norm(pair.second) == 0)
0808 {
0809
0810 ComplexType q = (z2 - z1) / (z1 - z0);
0811 auto P0 = g(z0);
0812 auto P1 = g(z1);
0813 ComplexType qp1 = static_cast<ComplexType>(1) + q;
0814 ComplexType A = q * (pair.first - qp1 * P1.first + q * P0.first);
0815
0816 ComplexType B = (static_cast<ComplexType>(2) * q + static_cast<ComplexType>(1)) * pair.first - qp1 * qp1 * P1.first + q * q * P0.first;
0817 ComplexType C = qp1 * pair.first;
0818 ComplexType rad = sqrt(B * B - static_cast<ComplexType>(4) * A * C);
0819 ComplexType denom1 = B + rad;
0820 ComplexType denom2 = B - rad;
0821 ComplexType correction = (z1 - z2) * static_cast<ComplexType>(2) * C;
0822 if (norm(denom1) > norm(denom2))
0823 {
0824 correction /= denom1;
0825 }
0826 else
0827 {
0828 correction /= denom2;
0829 }
0830
0831 z0 = z1;
0832 z1 = z2;
0833 z2 = z2 + correction;
0834 }
0835 else
0836 {
0837 z0 = z1;
0838 z1 = z2;
0839 z2 = z2 - (pair.first / pair.second);
0840 }
0841
0842
0843
0844
0845 Real tol = (max)(abs(z2) * std::numeric_limits<Real>::epsilon(), std::numeric_limits<Real>::epsilon());
0846 bool real_close = abs(z0.real() - z1.real()) < tol && abs(z0.real() - z2.real()) < tol && abs(z1.real() - z2.real()) < tol;
0847 bool imag_close = abs(z0.imag() - z1.imag()) < tol && abs(z0.imag() - z2.imag()) < tol && abs(z1.imag() - z2.imag()) < tol;
0848 if (real_close && imag_close)
0849 {
0850 return z2;
0851 }
0852
0853 } while (max_iterations--);
0854
0855
0856
0857
0858
0859
0860
0861 auto pair = g(z2);
0862 if (abs(pair.first) < sqrt(std::numeric_limits<Real>::epsilon()))
0863 {
0864 return z2;
0865 }
0866
0867 return { std::numeric_limits<Real>::quiet_NaN(),
0868 std::numeric_limits<Real>::quiet_NaN() };
0869 }
0870 #endif
0871
0872
0873 #if !defined(BOOST_MATH_NO_CXX17_IF_CONSTEXPR)
0874
0875 namespace detail
0876 {
0877 #if defined(BOOST_GNU_STDLIB) && !defined(_GLIBCXX_USE_C99_MATH_TR1)
0878 inline float fma_workaround(float x, float y, float z) { return ::fmaf(x, y, z); }
0879 inline double fma_workaround(double x, double y, double z) { return ::fma(x, y, z); }
0880 #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
0881 inline long double fma_workaround(long double x, long double y, long double z) { return ::fmal(x, y, z); }
0882 #endif
0883 #endif
0884 template<class T>
0885 inline T discriminant(T const& a, T const& b, T const& c)
0886 {
0887 T w = 4 * a * c;
0888 #if defined(BOOST_GNU_STDLIB) && !defined(_GLIBCXX_USE_C99_MATH_TR1)
0889 T e = fma_workaround(-c, 4 * a, w);
0890 T f = fma_workaround(b, b, -w);
0891 #else
0892 T e = std::fma(-c, 4 * a, w);
0893 T f = std::fma(b, b, -w);
0894 #endif
0895 return f + e;
0896 }
0897
0898 template<class T>
0899 std::pair<T, T> quadratic_roots_imp(T const& a, T const& b, T const& c)
0900 {
0901 #if defined(BOOST_GNU_STDLIB) && !defined(_GLIBCXX_USE_C99_MATH_TR1)
0902 using boost::math::copysign;
0903 #else
0904 using std::copysign;
0905 #endif
0906 using std::sqrt;
0907 if constexpr (std::is_floating_point<T>::value)
0908 {
0909 T nan = std::numeric_limits<T>::quiet_NaN();
0910 if (a == 0)
0911 {
0912 if (b == 0 && c != 0)
0913 {
0914 return std::pair<T, T>(nan, nan);
0915 }
0916 else if (b == 0 && c == 0)
0917 {
0918 return std::pair<T, T>(0, 0);
0919 }
0920 return std::pair<T, T>(-c / b, -c / b);
0921 }
0922 if (b == 0)
0923 {
0924 T x0_sq = -c / a;
0925 if (x0_sq < 0) {
0926 return std::pair<T, T>(nan, nan);
0927 }
0928 T x0 = sqrt(x0_sq);
0929 return std::pair<T, T>(-x0, x0);
0930 }
0931 T discriminant = detail::discriminant(a, b, c);
0932
0933
0934 if (discriminant < 0)
0935 {
0936 return std::pair<T, T>(nan, nan);
0937 }
0938 T q = -(b + copysign(sqrt(discriminant), b)) / T(2);
0939 T x0 = q / a;
0940 T x1 = c / q;
0941 if (x0 < x1)
0942 {
0943 return std::pair<T, T>(x0, x1);
0944 }
0945 return std::pair<T, T>(x1, x0);
0946 }
0947 else if constexpr (boost::math::tools::is_complex_type<T>::value)
0948 {
0949 typename T::value_type nan = std::numeric_limits<typename T::value_type>::quiet_NaN();
0950 if (a.real() == 0 && a.imag() == 0)
0951 {
0952 using std::norm;
0953 if (b.real() == 0 && b.imag() && norm(c) != 0)
0954 {
0955 return std::pair<T, T>({ nan, nan }, { nan, nan });
0956 }
0957 else if (b.real() == 0 && b.imag() && c.real() == 0 && c.imag() == 0)
0958 {
0959 return std::pair<T, T>({ 0,0 }, { 0,0 });
0960 }
0961 return std::pair<T, T>(-c / b, -c / b);
0962 }
0963 if (b.real() == 0 && b.imag() == 0)
0964 {
0965 T x0_sq = -c / a;
0966 T x0 = sqrt(x0_sq);
0967 return std::pair<T, T>(-x0, x0);
0968 }
0969
0970 T discriminant = b * b - T(4) * a * c;
0971 T q = -(b + sqrt(discriminant)) / T(2);
0972 return std::pair<T, T>(q / a, c / q);
0973 }
0974 else
0975 {
0976 T nan = std::numeric_limits<T>::quiet_NaN();
0977 if (a == 0)
0978 {
0979 if (b == 0 && c != 0)
0980 {
0981 return std::pair<T, T>(nan, nan);
0982 }
0983 else if (b == 0 && c == 0)
0984 {
0985 return std::pair<T, T>(0, 0);
0986 }
0987 return std::pair<T, T>(-c / b, -c / b);
0988 }
0989 if (b == 0)
0990 {
0991 T x0_sq = -c / a;
0992 if (x0_sq < 0) {
0993 return std::pair<T, T>(nan, nan);
0994 }
0995 T x0 = sqrt(x0_sq);
0996 return std::pair<T, T>(-x0, x0);
0997 }
0998 T discriminant = b * b - 4 * a * c;
0999 if (discriminant < 0)
1000 {
1001 return std::pair<T, T>(nan, nan);
1002 }
1003 T q = -(b + copysign(sqrt(discriminant), b)) / T(2);
1004 T x0 = q / a;
1005 T x1 = c / q;
1006 if (x0 < x1)
1007 {
1008 return std::pair<T, T>(x0, x1);
1009 }
1010 return std::pair<T, T>(x1, x0);
1011 }
1012 }
1013 }
1014
1015 template<class T1, class T2 = T1, class T3 = T1>
1016 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)
1017 {
1018 typedef typename tools::promote_args<T1, T2, T3>::type value_type;
1019 return detail::quadratic_roots_imp(static_cast<value_type>(a), static_cast<value_type>(b), static_cast<value_type>(c));
1020 }
1021
1022 #endif
1023
1024 }
1025 }
1026 }
1027
1028 #endif