File indexing completed on 2025-01-18 09:40:42
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 delta = (delta > 0) ? (result - min) / 2 : (result - max) / 2;
0279
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
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
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& , 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
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;
0373
0374
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;
0392 break;
0393 }
0394 multiplier *= e > 1024 ? 8 : 2;
0395 unpack_0(f(guess), f_current);
0396 }
0397 }
0398 else
0399 {
0400
0401
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;
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;
0436
0437
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;
0456 break;
0457 }
0458 multiplier *= e > 1024 ? 8 : 2;
0459 unpack_0(f(guess), f_current);
0460 }
0461 }
0462 else
0463 {
0464
0465
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;
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));
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
0522
0523
0524
0525
0526
0527
0528
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
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
0573
0574
0575
0576
0577
0578
0579
0580
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
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
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;
0609 }
0610
0611
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
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
0632
0633 delta = 0.99f * (guess - min);
0634 result = guess - delta;
0635 out_of_bounds_sentry = true;
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
0662
0663 delta = 0.99f * (guess - max);
0664 result = guess - delta;
0665 out_of_bounds_sentry = true;
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
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
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 }
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
0741 if (delta * ratio < 0)
0742 delta = ratio;
0743 }
0744 else
0745 delta = ratio;
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
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
0783
0784
0785
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
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
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
0837
0838
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
0850
0851
0852
0853
0854
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
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
0927
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
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
0969 {
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 }
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 }
1019 }
1020 }
1021
1022 #endif