1 // (C) Copyright John Maddock 2006.
2 // Use, modification and distribution are subject to the
3 // Boost Software License, Version 1.0. (See accompanying file
4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 #ifndef BOOST_MATH_TOOLS_NEWTON_SOLVER_HPP
7 #define BOOST_MATH_TOOLS_NEWTON_SOLVER_HPP
12 #include <boost/math/tools/complex.hpp> // test for multiprecision types.
16 #include <boost/config/no_tr1/cmath.hpp>
19 #include <boost/math/tools/config.hpp>
20 #include <boost/cstdint.hpp>
21 #include <boost/assert.hpp>
22 #include <boost/throw_exception.hpp>
26 #pragma warning(disable: 4512)
28 #include <boost/math/tools/tuple.hpp>
33 #include <boost/math/special_functions/sign.hpp>
34 #include <boost/math/special_functions/next.hpp>
35 #include <boost/math/tools/toms748_solve.hpp>
36 #include <boost/math/policies/error_handling.hpp>
46 template<int n, class T>
47 typename T::value_type get(const T&) BOOST_MATH_NOEXCEPT(T);
50 template <class Tuple, class T>
51 void unpack_tuple(const Tuple& t, T& a, T& b) BOOST_MATH_NOEXCEPT(T)
54 // Use ADL to find the right overload for get:
58 template <class Tuple, class T>
59 void unpack_tuple(const Tuple& t, T& a, T& b, T& c) BOOST_MATH_NOEXCEPT(T)
62 // Use ADL to find the right overload for get:
68 template <class Tuple, class T>
69 inline void unpack_0(const Tuple& t, T& val) BOOST_MATH_NOEXCEPT(T)
72 // Rely on ADL to find the correct overload of get:
76 template <class T, class U, class V>
77 inline void unpack_tuple(const std::pair<T, U>& p, V& a, V& b) BOOST_MATH_NOEXCEPT(T)
82 template <class T, class U, class V>
83 inline void unpack_0(const std::pair<T, U>& p, V& a) BOOST_MATH_NOEXCEPT(T)
88 template <class F, class T>
89 void handle_zero_derivative(F f,
96 const T& max) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
100 // this must be the first iteration, pretend that we had a
101 // previous one at either min or max:
110 unpack_0(f(guess), last_f0);
111 delta = guess - result;
113 if (sign(last_f0) * sign(f0) < 0)
115 // we've crossed over so move in opposite direction to last step:
118 delta = (result - min) / 2;
122 delta = (result - max) / 2;
127 // move in same direction as last step:
130 delta = (result - max) / 2;
134 delta = (result - min) / 2;
141 template <class F, class T, class Tol, class Policy>
142 std::pair<T, T> bisect(F f, T min, T max, Tol tol, boost::uintmax_t& max_iter, const Policy& pol) BOOST_NOEXCEPT_IF(policies::is_noexcept_error_policy<Policy>::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
149 return std::make_pair(min, min);
154 return std::make_pair(max, max);
160 static const char* function = "boost::math::tools::bisect<%1%>";
163 return boost::math::detail::pair_from_single(policies::raise_evaluation_error(function,
164 "Arguments in wrong order in boost::math::tools::bisect (first arg=%1%)", min, pol));
166 if (fmin * fmax >= 0)
168 return boost::math::detail::pair_from_single(policies::raise_evaluation_error(function,
169 "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));
173 // Three function invocations so far:
175 boost::uintmax_t count = max_iter;
181 while (count && (0 == tol(min, max)))
183 T mid = (min + max) / 2;
185 if ((mid == max) || (mid == min))
192 else if (sign(fmid) * sign(fmin) < 0)
206 #ifdef BOOST_MATH_INSTRUMENT
207 std::cout << "Bisection iteration, final count = " << max_iter << std::endl;
209 static boost::uintmax_t max_count = 0;
210 if (max_iter > max_count)
212 max_count = max_iter;
213 std::cout << "Maximum iterations: " << max_iter << std::endl;
217 return std::make_pair(min, max);
220 template <class F, class T, class Tol>
221 inline std::pair<T, T> bisect(F f, T min, T max, Tol tol, boost::uintmax_t& max_iter) BOOST_NOEXCEPT_IF(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
223 return bisect(f, min, max, tol, max_iter, policies::policy<>());
226 template <class F, class T, class Tol>
227 inline std::pair<T, T> bisect(F f, T min, T max, Tol tol) BOOST_NOEXCEPT_IF(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
229 boost::uintmax_t m = (std::numeric_limits<boost::uintmax_t>::max)();
230 return bisect(f, min, max, tol, m, policies::policy<>());
234 template <class F, class T>
235 T newton_raphson_iterate(F f, T guess, T min, T max, int digits, boost::uintmax_t& max_iter) BOOST_NOEXCEPT_IF(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
239 static const char* function = "boost::math::tools::newton_raphson_iterate<%1%>";
242 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<>());
245 T f0(0), f1, last_f0(0);
248 T factor = static_cast<T>(ldexp(1.0, 1 - digits));
249 T delta = tools::max_value<T>();
250 T delta1 = tools::max_value<T>();
251 T delta2 = tools::max_value<T>();
254 // We use these to sanity check that we do actually bracket a root,
255 // we update these to the function value when we update the endpoints
256 // of the range. Then, provided at some point we update both endpoints
257 // checking that max_range_f * min_range_f <= 0 verifies there is a root
258 // to be found somewhere. Note that if there is no root, and we approach
259 // a local minima, then the derivative will go to zero, and hence the next
260 // step will jump out of bounds (or at least past the minima), so this
261 // check *should* happen in pathological cases.
266 boost::uintmax_t count(max_iter);
268 #ifdef BOOST_MATH_INSTRUMENT
269 std::cout << "Newton_raphson_iterate, guess = " << guess << ", min = " << min << ", max = " << max
270 << ", digits = " << digits << ", max_iter = " << max_iter << std::endl;
277 detail::unpack_tuple(f(result), f0, f1);
283 // Oops zero derivative!!!
284 #ifdef BOOST_MATH_INSTRUMENT
285 std::cout << "Newton iteration, zero derivative found!" << std::endl;
287 detail::handle_zero_derivative(f, last_f0, f0, delta, result, guess, min, max);
293 #ifdef BOOST_MATH_INSTRUMENT
294 std::cout << "Newton iteration " << max_iter - count << ", delta = " << delta << std::endl;
296 if (fabs(delta * 2) > fabs(delta2))
298 // Last two steps haven't converged.
299 T shift = (delta > 0) ? (result - min) / 2 : (result - max) / 2;
300 if ((result != 0) && (fabs(shift) > fabs(result)))
302 delta = sign(delta) * fabs(result) * 1.1f; // Protect against huge jumps!
303 //delta = sign(delta) * result; // Protect against huge jumps! Failed for negative result. https://github.com/boostorg/math/issues/216
307 // reset delta1/2 so we don't take this branch next time round:
315 delta = 0.5F * (guess - min);
316 result = guess - delta;
317 if ((result == min) || (result == max))
320 else if (result >= max)
322 delta = 0.5F * (guess - max);
323 result = guess - delta;
324 if ((result == min) || (result == max))
339 // Sanity check that we bracket the root:
341 if (max_range_f * min_range_f > 0)
343 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<>());
345 }while(count && (fabs(result * factor) < fabs(delta)));
349 #ifdef BOOST_MATH_INSTRUMENT
350 std::cout << "Newton Raphson final iteration count = " << max_iter << std::endl;
352 static boost::uintmax_t max_count = 0;
353 if (max_iter > max_count)
355 max_count = max_iter;
356 // std::cout << "Maximum iterations: " << max_iter << std::endl;
357 // Puzzled what this tells us, so commented out for now?
364 template <class F, class T>
365 inline T newton_raphson_iterate(F f, T guess, T min, T max, int digits) BOOST_NOEXCEPT_IF(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
367 boost::uintmax_t m = (std::numeric_limits<boost::uintmax_t>::max)();
368 return newton_raphson_iterate(f, guess, min, max, digits, m);
376 static T step(const T& /*x*/, const T& f0, const T& f1, const T& f2) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(T))
380 T num = 2 * f1 - f0 * (f2 / f1);
383 BOOST_MATH_INSTRUMENT_VARIABLE(denom);
384 BOOST_MATH_INSTRUMENT_VARIABLE(num);
386 if ((fabs(num) < 1) && (fabs(denom) >= fabs(num) * tools::max_value<T>()))
388 // possible overflow, use Newton step:
397 template <class F, class T>
398 T bracket_root_towards_min(F f, T guess, const T& f0, T& min, T& max, boost::uintmax_t& count) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())));
400 template <class F, class T>
401 T bracket_root_towards_max(F f, T guess, const T& f0, T& min, T& max, boost::uintmax_t& count) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
405 // Move guess towards max until we bracket the root, updating min and max as we go:
410 if (fabs(min) < fabs(max))
412 while (--count && ((f_current < 0) == (f0 < 0)))
419 f_current = -f_current; // There must be a change of sign!
423 unpack_0(f(guess), f_current);
429 // If min and max are negative we have to divide to head towards max:
431 while (--count && ((f_current < 0) == (f0 < 0)))
438 f_current = -f_current; // There must be a change of sign!
442 unpack_0(f(guess), f_current);
450 return (guess0 - guess) + bracket_root_towards_min(f, guess, f_current, min, max, count);
452 return guess0 - (max + min) / 2;
455 template <class F, class T>
456 T bracket_root_towards_min(F f, T guess, const T& f0, T& min, T& max, boost::uintmax_t& count) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
460 // Move guess towards min until we bracket the root, updating min and max as we go:
466 if (fabs(min) < fabs(max))
468 while (--count && ((f_current < 0) == (f0 < 0)))
475 f_current = -f_current; // There must be a change of sign!
479 unpack_0(f(guess), f_current);
485 // If min and max are negative we have to multiply to head towards min:
487 while (--count && ((f_current < 0) == (f0 < 0)))
494 f_current = -f_current; // There must be a change of sign!
498 unpack_0(f(guess), f_current);
506 return (guess0 - guess) + bracket_root_towards_max(f, guess, f_current, min, max, count);
508 return guess0 - (max + min) / 2;
511 template <class Stepper, class F, class T>
512 T second_order_root_finder(F f, T guess, T min, T max, int digits, boost::uintmax_t& max_iter) BOOST_NOEXCEPT_IF(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
516 #ifdef BOOST_MATH_INSTRUMENT
517 std::cout << "Second order root iteration, guess = " << guess << ", min = " << min << ", max = " << max
518 << ", digits = " << digits << ", max_iter = " << max_iter << std::endl;
520 static const char* function = "boost::math::tools::halley_iterate<%1%>";
523 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<>());
529 T factor = ldexp(static_cast<T>(1.0), 1 - digits);
530 T delta = (std::max)(T(10000000 * guess), T(10000000)); // arbitarily large delta
534 bool out_of_bounds_sentry = false;
536 #ifdef BOOST_MATH_INSTRUMENT
537 std::cout << "Second order root iteration, limit = " << factor << std::endl;
541 // We use these to sanity check that we do actually bracket a root,
542 // we update these to the function value when we update the endpoints
543 // of the range. Then, provided at some point we update both endpoints
544 // checking that max_range_f * min_range_f <= 0 verifies there is a root
545 // to be found somewhere. Note that if there is no root, and we approach
546 // a local minima, then the derivative will go to zero, and hence the next
547 // step will jump out of bounds (or at least past the minima), so this
548 // check *should* happen in pathological cases.
553 boost::uintmax_t count(max_iter);
559 detail::unpack_tuple(f(result), f0, f1, f2);
562 BOOST_MATH_INSTRUMENT_VARIABLE(f0);
563 BOOST_MATH_INSTRUMENT_VARIABLE(f1);
564 BOOST_MATH_INSTRUMENT_VARIABLE(f2);
570 // Oops zero derivative!!!
571 #ifdef BOOST_MATH_INSTRUMENT
572 std::cout << "Second order root iteration, zero derivative found!" << std::endl;
574 detail::handle_zero_derivative(f, last_f0, f0, delta, result, guess, min, max);
580 delta = Stepper::step(result, f0, f1, f2);
581 if (delta * f1 / f0 < 0)
583 // Oh dear, we have a problem as Newton and Halley steps
584 // disagree about which way we should move. Probably
585 // there is cancelation error in the calculation of the
586 // Halley step, or else the derivatives are so small
587 // that their values are basically trash. We will move
588 // in the direction indicated by a Newton step, but
589 // by no more than twice the current guess value, otherwise
590 // we can jump way out of bounds if we're not careful.
591 // See https://svn.boost.org/trac/boost/ticket/8314.
593 if (fabs(delta) > 2 * fabs(guess))
594 delta = (delta < 0 ? -1 : 1) * 2 * fabs(guess);
600 #ifdef BOOST_MATH_INSTRUMENT
601 std::cout << "Second order root iteration, delta = " << delta << std::endl;
603 T convergence = fabs(delta / delta2);
604 if ((convergence > 0.8) && (convergence < 2))
606 // last two steps haven't converged.
607 delta = (delta > 0) ? (result - min) / 2 : (result - max) / 2;
608 if ((result != 0) && (fabs(delta) > result))
609 delta = sign(delta) * fabs(result) * 0.9f; // protect against huge jumps!
610 // reset delta2 so that this branch will *not* be taken on the
614 BOOST_MATH_INSTRUMENT_VARIABLE(delta);
618 BOOST_MATH_INSTRUMENT_VARIABLE(result);
620 // check for out of bounds step:
623 T diff = ((fabs(min) < 1) && (fabs(result) > 1) && (tools::max_value<T>() / fabs(result) < fabs(min)))
625 : (fabs(min) < 1) && (fabs(tools::max_value<T>() * min) < fabs(result))
626 ? ((min < 0) != (result < 0)) ? -tools::max_value<T>() : tools::max_value<T>() : T(result / min);
629 if (!out_of_bounds_sentry && (diff > 0) && (diff < 3))
631 // Only a small out of bounds step, lets assume that the result
632 // is probably approximately at min:
633 delta = 0.99f * (guess - min);
634 result = guess - delta;
635 out_of_bounds_sentry = true; // only take this branch once!
639 if (fabs(float_distance(min, max)) < 2)
641 result = guess = (min + max) / 2;
644 delta = bracket_root_towards_min(f, guess, f0, min, max, count);
645 result = guess - delta;
650 else if (result > max)
652 T diff = ((fabs(max) < 1) && (fabs(result) > 1) && (tools::max_value<T>() / fabs(result) < fabs(max))) ? T(1000) : T(result / max);
655 if (!out_of_bounds_sentry && (diff > 0) && (diff < 3))
657 // Only a small out of bounds step, lets assume that the result
658 // is probably approximately at min:
659 delta = 0.99f * (guess - max);
660 result = guess - delta;
661 out_of_bounds_sentry = true; // only take this branch once!
665 if (fabs(float_distance(min, max)) < 2)
667 result = guess = (min + max) / 2;
670 delta = bracket_root_towards_max(f, guess, f0, min, max, count);
671 result = guess - delta;
688 // Sanity check that we bracket the root:
690 if (max_range_f * min_range_f > 0)
692 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<>());
694 } while(count && (fabs(result * factor) < fabs(delta)));
698 #ifdef BOOST_MATH_INSTRUMENT
699 std::cout << "Second order root finder, final iteration count = " << max_iter << std::endl;
704 } // T second_order_root_finder
706 template <class F, class T>
707 T halley_iterate(F f, T guess, T min, T max, int digits, boost::uintmax_t& max_iter) BOOST_NOEXCEPT_IF(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
709 return detail::second_order_root_finder<detail::halley_step>(f, guess, min, max, digits, max_iter);
712 template <class F, class T>
713 inline T halley_iterate(F f, T guess, T min, T max, int digits) BOOST_NOEXCEPT_IF(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
715 boost::uintmax_t m = (std::numeric_limits<boost::uintmax_t>::max)();
716 return halley_iterate(f, guess, min, max, digits, m);
721 struct schroder_stepper
724 static T step(const T& x, const T& f0, const T& f1, const T& f2) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(T))
729 if ((x != 0) && (fabs(ratio / x) < 0.1))
731 delta = ratio + (f2 / (2 * f1)) * ratio * ratio;
732 // check second derivative doesn't over compensate:
733 if (delta * ratio < 0)
737 delta = ratio; // fall back to Newton iteration.
744 template <class F, class T>
745 T schroder_iterate(F f, T guess, T min, T max, int digits, boost::uintmax_t& max_iter) BOOST_NOEXCEPT_IF(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
747 return detail::second_order_root_finder<detail::schroder_stepper>(f, guess, min, max, digits, max_iter);
750 template <class F, class T>
751 inline T schroder_iterate(F f, T guess, T min, T max, int digits) BOOST_NOEXCEPT_IF(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
753 boost::uintmax_t m = (std::numeric_limits<boost::uintmax_t>::max)();
754 return schroder_iterate(f, guess, min, max, digits, m);
757 // These two are the old spelling of this function, retained for backwards compatibity just in case:
759 template <class F, class T>
760 T schroeder_iterate(F f, T guess, T min, T max, int digits, boost::uintmax_t& max_iter) BOOST_NOEXCEPT_IF(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
762 return detail::second_order_root_finder<detail::schroder_stepper>(f, guess, min, max, digits, max_iter);
765 template <class F, class T>
766 inline T schroeder_iterate(F f, T guess, T min, T max, int digits) BOOST_NOEXCEPT_IF(policies::is_noexcept_error_policy<policies::policy<> >::value&& BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
768 boost::uintmax_t m = (std::numeric_limits<boost::uintmax_t>::max)();
769 return schroder_iterate(f, guess, min, max, digits, m);
772 #ifndef BOOST_NO_CXX11_AUTO_DECLARATIONS
774 * Why do we set the default maximum number of iterations to the number of digits in the type?
775 * Because for double roots, the number of digits increases linearly with the number of iterations,
776 * so this default should recover full precision even in this somewhat pathological case.
777 * For isolated roots, the problem is so rapidly convergent that this doesn't matter at all.
779 template<class Complex, class F>
780 Complex complex_newton(F g, Complex guess, int max_iterations = std::numeric_limits<typename Complex::value_type>::digits)
782 typedef typename Complex::value_type Real;
786 // z0, z1, and z2 cannot be the same, in case we immediately need to resort to Muller's Method:
787 Complex z0 = guess + Complex(1, 0);
788 Complex z1 = guess + Complex(0, 1);
793 if (norm(pair.second) == 0)
795 // Muller's method. Notation follows Numerical Recipes, 9.5.2:
796 Complex q = (z2 - z1) / (z1 - z0);
799 Complex qp1 = static_cast<Complex>(1) + q;
800 Complex A = q * (pair.first - qp1 * P1.first + q * P0.first);
802 Complex B = (static_cast<Complex>(2) * q + static_cast<Complex>(1)) * pair.first - qp1 * qp1 * P1.first + q * q * P0.first;
803 Complex C = qp1 * pair.first;
804 Complex rad = sqrt(B * B - static_cast<Complex>(4) * A * C);
805 Complex denom1 = B + rad;
806 Complex denom2 = B - rad;
807 Complex correction = (z1 - z2) * static_cast<Complex>(2) * C;
808 if (norm(denom1) > norm(denom2))
810 correction /= denom1;
814 correction /= denom2;
819 z2 = z2 + correction;
825 z2 = z2 - (pair.first / pair.second);
828 // See: https://math.stackexchange.com/questions/3017766/constructing-newton-iteration-converging-to-non-root
829 // If f' is continuous, then convergence of x_n -> x* implies f(x*) = 0.
830 // This condition approximates this convergence condition by requiring three consecutive iterates to be clustered.
831 Real tol = (max)(abs(z2) * std::numeric_limits<Real>::epsilon(), std::numeric_limits<Real>::epsilon());
832 bool real_close = abs(z0.real() - z1.real()) < tol && abs(z0.real() - z2.real()) < tol && abs(z1.real() - z2.real()) < tol;
833 bool imag_close = abs(z0.imag() - z1.imag()) < tol && abs(z0.imag() - z2.imag()) < tol && abs(z1.imag() - z2.imag()) < tol;
834 if (real_close && imag_close)
839 } while (max_iterations--);
841 // The idea is that if we can get abs(f) < eps, we should, but if we go through all these iterations
842 // and abs(f) < sqrt(eps), then roundoff error simply does not allow that we can evaluate f to < eps
843 // This is somewhat awkward as it isn't scale invariant, but using the Daubechies coefficient example code,
844 // I found this condition generates correct roots, whereas the scale invariant condition discussed here:
845 // https://scicomp.stackexchange.com/questions/30597/defining-a-condition-number-and-termination-criteria-for-newtons-method
846 // allows nonroots to be passed off as roots.
848 if (abs(pair.first) < sqrt(std::numeric_limits<Real>::epsilon()))
853 return { std::numeric_limits<Real>::quiet_NaN(),
854 std::numeric_limits<Real>::quiet_NaN() };
859 #if !defined(BOOST_NO_CXX17_IF_CONSTEXPR)
860 // https://stackoverflow.com/questions/48979861/numerically-stable-method-for-solving-quadratic-equations/50065711
863 #if defined(BOOST_GNU_STDLIB) && !defined(_GLIBCXX_USE_C99_MATH_TR1)
864 float fma_workaround(float f) { return ::fmaf(f); }
865 double fma_workaround(double f) { return ::fma(f); }
866 #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
867 long double fma_workaround(long double f) { return ::fmal(f); }
871 inline T discriminant(T const& a, T const& b, T const& c)
874 #if defined(BOOST_GNU_STDLIB) && !defined(_GLIBCXX_USE_C99_MATH_TR1)
875 T e = fma_workaround(-c, 4 * a, w);
876 T f = fma_workaround(b, b, -w);
878 T e = std::fma(-c, 4 * a, w);
879 T f = std::fma(b, b, -w);
885 std::pair<T, T> quadratic_roots_imp(T const& a, T const& b, T const& c)
889 if constexpr (std::is_floating_point<T>::value)
891 T nan = std::numeric_limits<T>::quiet_NaN();
894 if (b == 0 && c != 0)
896 return std::pair<T, T>(nan, nan);
898 else if (b == 0 && c == 0)
900 return std::pair<T, T>(0, 0);
902 return std::pair<T, T>(-c / b, -c / b);
908 return std::pair<T, T>(nan, nan);
911 return std::pair<T, T>(-x0, x0);
913 T discriminant = detail::discriminant(a, b, c);
914 // Is there a sane way to flush very small negative values to zero?
915 // If there is I don't know of it.
916 if (discriminant < 0)
918 return std::pair<T, T>(nan, nan);
920 T q = -(b + copysign(sqrt(discriminant), b)) / T(2);
925 return std::pair<T, T>(x0, x1);
927 return std::pair<T, T>(x1, x0);
929 else if constexpr (boost::math::tools::is_complex_type<T>::value)
931 typename T::value_type nan = std::numeric_limits<typename T::value_type>::quiet_NaN();
932 if (a.real() == 0 && a.imag() == 0)
935 if (b.real() == 0 && b.imag() && norm(c) != 0)
937 return std::pair<T, T>({ nan, nan }, { nan, nan });
939 else if (b.real() == 0 && b.imag() && c.real() == 0 && c.imag() == 0)
941 return std::pair<T, T>({ 0,0 }, { 0,0 });
943 return std::pair<T, T>(-c / b, -c / b);
945 if (b.real() == 0 && b.imag() == 0)
949 return std::pair<T, T>(-x0, x0);
951 // There's no fma for complex types:
952 T discriminant = b * b - T(4) * a * c;
953 T q = -(b + sqrt(discriminant)) / T(2);
954 return std::pair<T, T>(q / a, c / q);
956 else // Most likely the type is a boost.multiprecision.
957 { //There is no fma for multiprecision, and in addition it doesn't seem to be useful, so revert to the naive computation.
958 T nan = std::numeric_limits<T>::quiet_NaN();
961 if (b == 0 && c != 0)
963 return std::pair<T, T>(nan, nan);
965 else if (b == 0 && c == 0)
967 return std::pair<T, T>(0, 0);
969 return std::pair<T, T>(-c / b, -c / b);
975 return std::pair<T, T>(nan, nan);
978 return std::pair<T, T>(-x0, x0);
980 T discriminant = b * b - 4 * a * c;
981 if (discriminant < 0)
983 return std::pair<T, T>(nan, nan);
985 T q = -(b + copysign(sqrt(discriminant), b)) / T(2);
990 return std::pair<T, T>(x0, x1);
992 return std::pair<T, T>(x1, x0);
995 } // namespace detail
997 template<class T1, class T2 = T1, class T3 = T1>
998 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)
1000 typedef typename tools::promote_args<T1, T2, T3>::type value_type;
1001 return detail::quadratic_roots_imp(static_cast<value_type>(a), static_cast<value_type>(b), static_cast<value_type>(c));
1006 } // namespace tools
1008 } // namespace boost
1010 #endif // BOOST_MATH_TOOLS_NEWTON_SOLVER_HPP