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)
5
6 #ifndef BOOST_MATH_TOOLS_NEWTON_SOLVER_HPP
7 #define BOOST_MATH_TOOLS_NEWTON_SOLVER_HPP
8
9 #ifdef _MSC_VER
10 #pragma once
11 #endif
12 #include <boost/math/tools/complex.hpp> // test for multiprecision types.
13
14 #include <iostream>
15 #include <utility>
16 #include <boost/config/no_tr1/cmath.hpp>
17 #include <stdexcept>
18
19 #include <boost/math/tools/config.hpp>
20 #include <boost/cstdint.hpp>
21 #include <boost/assert.hpp>
22 #include <boost/throw_exception.hpp>
23 #include <boost/math/tools/cxx03_warn.hpp>
24
25 #ifdef BOOST_MSVC
26 #pragma warning(push)
27 #pragma warning(disable: 4512)
28 #endif
29 #include <boost/math/tools/tuple.hpp>
30 #ifdef BOOST_MSVC
31 #pragma warning(pop)
32 #endif
33
34 #include <boost/math/special_functions/sign.hpp>
35 #include <boost/math/special_functions/next.hpp>
36 #include <boost/math/tools/toms748_solve.hpp>
37 #include <boost/math/policies/error_handling.hpp>
38
39 namespace boost {
40 namespace math {
41 namespace tools {
42
43 namespace detail {
44
45 namespace dummy {
46
47 template<int n, class T>
48 typename T::value_type get(const T&) BOOST_MATH_NOEXCEPT(T);
49 }
50
51 template <class Tuple, class T>
unpack_tuple(const Tuple & t,T & a,T & b)52 void unpack_tuple(const Tuple& t, T& a, T& b) BOOST_MATH_NOEXCEPT(T)
53 {
54 using dummy::get;
55 // Use ADL to find the right overload for get:
56 a = get<0>(t);
57 b = get<1>(t);
58 }
59 template <class Tuple, class T>
unpack_tuple(const Tuple & t,T & a,T & b,T & c)60 void unpack_tuple(const Tuple& t, T& a, T& b, T& c) BOOST_MATH_NOEXCEPT(T)
61 {
62 using dummy::get;
63 // Use ADL to find the right overload for get:
64 a = get<0>(t);
65 b = get<1>(t);
66 c = get<2>(t);
67 }
68
69 template <class Tuple, class T>
unpack_0(const Tuple & t,T & val)70 inline void unpack_0(const Tuple& t, T& val) BOOST_MATH_NOEXCEPT(T)
71 {
72 using dummy::get;
73 // Rely on ADL to find the correct overload of get:
74 val = get<0>(t);
75 }
76
77 template <class T, class U, class V>
unpack_tuple(const std::pair<T,U> & p,V & a,V & b)78 inline void unpack_tuple(const std::pair<T, U>& p, V& a, V& b) BOOST_MATH_NOEXCEPT(T)
79 {
80 a = p.first;
81 b = p.second;
82 }
83 template <class T, class U, class V>
unpack_0(const std::pair<T,U> & p,V & a)84 inline void unpack_0(const std::pair<T, U>& p, V& a) BOOST_MATH_NOEXCEPT(T)
85 {
86 a = p.first;
87 }
88
89 template <class F, class T>
handle_zero_derivative(F f,T & last_f0,const T & f0,T & delta,T & result,T & guess,const T & min,const T & max)90 void handle_zero_derivative(F f,
91 T& last_f0,
92 const T& f0,
93 T& delta,
94 T& result,
95 T& guess,
96 const T& min,
97 const T& max) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
98 {
99 if (last_f0 == 0)
100 {
101 // this must be the first iteration, pretend that we had a
102 // previous one at either min or max:
103 if (result == min)
104 {
105 guess = max;
106 }
107 else
108 {
109 guess = min;
110 }
111 unpack_0(f(guess), last_f0);
112 delta = guess - result;
113 }
114 if (sign(last_f0) * sign(f0) < 0)
115 {
116 // we've crossed over so move in opposite direction to last step:
117 if (delta < 0)
118 {
119 delta = (result - min) / 2;
120 }
121 else
122 {
123 delta = (result - max) / 2;
124 }
125 }
126 else
127 {
128 // move in same direction as last step:
129 if (delta < 0)
130 {
131 delta = (result - max) / 2;
132 }
133 else
134 {
135 delta = (result - min) / 2;
136 }
137 }
138 }
139
140 } // namespace
141
142 template <class F, class T, class Tol, class Policy>
bisect(F f,T min,T max,Tol tol,boost::uintmax_t & max_iter,const Policy & pol)143 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>())))
144 {
145 T fmin = f(min);
146 T fmax = f(max);
147 if (fmin == 0)
148 {
149 max_iter = 2;
150 return std::make_pair(min, min);
151 }
152 if (fmax == 0)
153 {
154 max_iter = 2;
155 return std::make_pair(max, max);
156 }
157
158 //
159 // Error checking:
160 //
161 static const char* function = "boost::math::tools::bisect<%1%>";
162 if (min >= max)
163 {
164 return boost::math::detail::pair_from_single(policies::raise_evaluation_error(function,
165 "Arguments in wrong order in boost::math::tools::bisect (first arg=%1%)", min, pol));
166 }
167 if (fmin * fmax >= 0)
168 {
169 return boost::math::detail::pair_from_single(policies::raise_evaluation_error(function,
170 "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));
171 }
172
173 //
174 // Three function invocations so far:
175 //
176 boost::uintmax_t count = max_iter;
177 if (count < 3)
178 count = 0;
179 else
180 count -= 3;
181
182 while (count && (0 == tol(min, max)))
183 {
184 T mid = (min + max) / 2;
185 T fmid = f(mid);
186 if ((mid == max) || (mid == min))
187 break;
188 if (fmid == 0)
189 {
190 min = max = mid;
191 break;
192 }
193 else if (sign(fmid) * sign(fmin) < 0)
194 {
195 max = mid;
196 }
197 else
198 {
199 min = mid;
200 fmin = fmid;
201 }
202 --count;
203 }
204
205 max_iter -= count;
206
207 #ifdef BOOST_MATH_INSTRUMENT
208 std::cout << "Bisection iteration, final count = " << max_iter << std::endl;
209
210 static boost::uintmax_t max_count = 0;
211 if (max_iter > max_count)
212 {
213 max_count = max_iter;
214 std::cout << "Maximum iterations: " << max_iter << std::endl;
215 }
216 #endif
217
218 return std::make_pair(min, max);
219 }
220
221 template <class F, class T, class Tol>
bisect(F f,T min,T max,Tol tol,boost::uintmax_t & max_iter)222 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 {
224 return bisect(f, min, max, tol, max_iter, policies::policy<>());
225 }
226
227 template <class F, class T, class Tol>
bisect(F f,T min,T max,Tol tol)228 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 {
230 boost::uintmax_t m = (std::numeric_limits<boost::uintmax_t>::max)();
231 return bisect(f, min, max, tol, m, policies::policy<>());
232 }
233
234
235 template <class F, class T>
newton_raphson_iterate(F f,T guess,T min,T max,int digits,boost::uintmax_t & max_iter)236 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>())))
237 {
238 BOOST_MATH_STD_USING
239
240 static const char* function = "boost::math::tools::newton_raphson_iterate<%1%>";
241 if (min >= max)
242 {
243 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<>());
244 }
245
246 T f0(0), f1, last_f0(0);
247 T result = guess;
248
249 T factor = static_cast<T>(ldexp(1.0, 1 - digits));
250 T delta = tools::max_value<T>();
251 T delta1 = tools::max_value<T>();
252 T delta2 = tools::max_value<T>();
253
254 //
255 // We use these to sanity check that we do actually bracket a root,
256 // we update these to the function value when we update the endpoints
257 // of the range. Then, provided at some point we update both endpoints
258 // checking that max_range_f * min_range_f <= 0 verifies there is a root
259 // to be found somewhere. Note that if there is no root, and we approach
260 // a local minima, then the derivative will go to zero, and hence the next
261 // step will jump out of bounds (or at least past the minima), so this
262 // check *should* happen in pathological cases.
263 //
264 T max_range_f = 0;
265 T min_range_f = 0;
266
267 boost::uintmax_t count(max_iter);
268
269 #ifdef BOOST_MATH_INSTRUMENT
270 std::cout << "Newton_raphson_iterate, guess = " << guess << ", min = " << min << ", max = " << max
271 << ", digits = " << digits << ", max_iter = " << max_iter << std::endl;
272 #endif
273
274 do {
275 last_f0 = f0;
276 delta2 = delta1;
277 delta1 = delta;
278 detail::unpack_tuple(f(result), f0, f1);
279 --count;
280 if (0 == f0)
281 break;
282 if (f1 == 0)
283 {
284 // Oops zero derivative!!!
285 #ifdef BOOST_MATH_INSTRUMENT
286 std::cout << "Newton iteration, zero derivative found!" << std::endl;
287 #endif
288 detail::handle_zero_derivative(f, last_f0, f0, delta, result, guess, min, max);
289 }
290 else
291 {
292 delta = f0 / f1;
293 }
294 #ifdef BOOST_MATH_INSTRUMENT
295 std::cout << "Newton iteration " << max_iter - count << ", delta = " << delta << std::endl;
296 #endif
297 if (fabs(delta * 2) > fabs(delta2))
298 {
299 // Last two steps haven't converged.
300 T shift = (delta > 0) ? (result - min) / 2 : (result - max) / 2;
301 if ((result != 0) && (fabs(shift) > fabs(result)))
302 {
303 delta = sign(delta) * fabs(result) * 1.1f; // Protect against huge jumps!
304 //delta = sign(delta) * result; // Protect against huge jumps! Failed for negative result. https://github.com/boostorg/math/issues/216
305 }
306 else
307 delta = shift;
308 // reset delta1/2 so we don't take this branch next time round:
309 delta1 = 3 * delta;
310 delta2 = 3 * delta;
311 }
312 guess = result;
313 result -= delta;
314 if (result <= min)
315 {
316 delta = 0.5F * (guess - min);
317 result = guess - delta;
318 if ((result == min) || (result == max))
319 break;
320 }
321 else if (result >= max)
322 {
323 delta = 0.5F * (guess - max);
324 result = guess - delta;
325 if ((result == min) || (result == max))
326 break;
327 }
328 // Update brackets:
329 if (delta > 0)
330 {
331 max = guess;
332 max_range_f = f0;
333 }
334 else
335 {
336 min = guess;
337 min_range_f = f0;
338 }
339 //
340 // Sanity check that we bracket the root:
341 //
342 if (max_range_f * min_range_f > 0)
343 {
344 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 }
346 }while(count && (fabs(result * factor) < fabs(delta)));
347
348 max_iter -= count;
349
350 #ifdef BOOST_MATH_INSTRUMENT
351 std::cout << "Newton Raphson final iteration count = " << max_iter << std::endl;
352
353 static boost::uintmax_t max_count = 0;
354 if (max_iter > max_count)
355 {
356 max_count = max_iter;
357 // std::cout << "Maximum iterations: " << max_iter << std::endl;
358 // Puzzled what this tells us, so commented out for now?
359 }
360 #endif
361
362 return result;
363 }
364
365 template <class F, class T>
newton_raphson_iterate(F f,T guess,T min,T max,int digits)366 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 {
368 boost::uintmax_t m = (std::numeric_limits<boost::uintmax_t>::max)();
369 return newton_raphson_iterate(f, guess, min, max, digits, m);
370 }
371
372 namespace detail {
373
374 struct halley_step
375 {
376 template <class T>
stepboost::math::tools::detail::halley_step377 static T step(const T& /*x*/, const T& f0, const T& f1, const T& f2) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(T))
378 {
379 using std::fabs;
380 T denom = 2 * f0;
381 T num = 2 * f1 - f0 * (f2 / f1);
382 T delta;
383
384 BOOST_MATH_INSTRUMENT_VARIABLE(denom);
385 BOOST_MATH_INSTRUMENT_VARIABLE(num);
386
387 if ((fabs(num) < 1) && (fabs(denom) >= fabs(num) * tools::max_value<T>()))
388 {
389 // possible overflow, use Newton step:
390 delta = f0 / f1;
391 }
392 else
393 delta = denom / num;
394 return delta;
395 }
396 };
397
398 template <class F, class T>
399 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
401 template <class F, class T>
bracket_root_towards_max(F f,T guess,const T & f0,T & min,T & max,boost::uintmax_t & count)402 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>())))
403 {
404 using std::fabs;
405 //
406 // Move guess towards max until we bracket the root, updating min and max as we go:
407 //
408 T guess0 = guess;
409 T multiplier = 2;
410 T f_current = f0;
411 if (fabs(min) < fabs(max))
412 {
413 while (--count && ((f_current < 0) == (f0 < 0)))
414 {
415 min = guess;
416 guess *= multiplier;
417 if (guess > max)
418 {
419 guess = max;
420 f_current = -f_current; // There must be a change of sign!
421 break;
422 }
423 multiplier *= 2;
424 unpack_0(f(guess), f_current);
425 }
426 }
427 else
428 {
429 //
430 // If min and max are negative we have to divide to head towards max:
431 //
432 while (--count && ((f_current < 0) == (f0 < 0)))
433 {
434 min = guess;
435 guess /= multiplier;
436 if (guess > max)
437 {
438 guess = max;
439 f_current = -f_current; // There must be a change of sign!
440 break;
441 }
442 multiplier *= 2;
443 unpack_0(f(guess), f_current);
444 }
445 }
446
447 if (count)
448 {
449 max = guess;
450 if (multiplier > 16)
451 return (guess0 - guess) + bracket_root_towards_min(f, guess, f_current, min, max, count);
452 }
453 return guess0 - (max + min) / 2;
454 }
455
456 template <class F, class T>
bracket_root_towards_min(F f,T guess,const T & f0,T & min,T & max,boost::uintmax_t & count)457 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>())))
458 {
459 using std::fabs;
460 //
461 // Move guess towards min until we bracket the root, updating min and max as we go:
462 //
463 T guess0 = guess;
464 T multiplier = 2;
465 T f_current = f0;
466
467 if (fabs(min) < fabs(max))
468 {
469 while (--count && ((f_current < 0) == (f0 < 0)))
470 {
471 max = guess;
472 guess /= multiplier;
473 if (guess < min)
474 {
475 guess = min;
476 f_current = -f_current; // There must be a change of sign!
477 break;
478 }
479 multiplier *= 2;
480 unpack_0(f(guess), f_current);
481 }
482 }
483 else
484 {
485 //
486 // If min and max are negative we have to multiply to head towards min:
487 //
488 while (--count && ((f_current < 0) == (f0 < 0)))
489 {
490 max = guess;
491 guess *= multiplier;
492 if (guess < min)
493 {
494 guess = min;
495 f_current = -f_current; // There must be a change of sign!
496 break;
497 }
498 multiplier *= 2;
499 unpack_0(f(guess), f_current);
500 }
501 }
502
503 if (count)
504 {
505 min = guess;
506 if (multiplier > 16)
507 return (guess0 - guess) + bracket_root_towards_max(f, guess, f_current, min, max, count);
508 }
509 return guess0 - (max + min) / 2;
510 }
511
512 template <class Stepper, class F, class T>
second_order_root_finder(F f,T guess,T min,T max,int digits,boost::uintmax_t & max_iter)513 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>())))
514 {
515 BOOST_MATH_STD_USING
516
517 #ifdef BOOST_MATH_INSTRUMENT
518 std::cout << "Second order root iteration, guess = " << guess << ", min = " << min << ", max = " << max
519 << ", digits = " << digits << ", max_iter = " << max_iter << std::endl;
520 #endif
521 static const char* function = "boost::math::tools::halley_iterate<%1%>";
522 if (min >= max)
523 {
524 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<>());
525 }
526
527 T f0(0), f1, f2;
528 T result = guess;
529
530 T factor = ldexp(static_cast<T>(1.0), 1 - digits);
531 T delta = (std::max)(T(10000000 * guess), T(10000000)); // arbitrarily large delta
532 T last_f0 = 0;
533 T delta1 = delta;
534 T delta2 = delta;
535 bool out_of_bounds_sentry = false;
536
537 #ifdef BOOST_MATH_INSTRUMENT
538 std::cout << "Second order root iteration, limit = " << factor << std::endl;
539 #endif
540
541 //
542 // We use these to sanity check that we do actually bracket a root,
543 // we update these to the function value when we update the endpoints
544 // of the range. Then, provided at some point we update both endpoints
545 // checking that max_range_f * min_range_f <= 0 verifies there is a root
546 // to be found somewhere. Note that if there is no root, and we approach
547 // a local minima, then the derivative will go to zero, and hence the next
548 // step will jump out of bounds (or at least past the minima), so this
549 // check *should* happen in pathological cases.
550 //
551 T max_range_f = 0;
552 T min_range_f = 0;
553
554 boost::uintmax_t count(max_iter);
555
556 do {
557 last_f0 = f0;
558 delta2 = delta1;
559 delta1 = delta;
560 detail::unpack_tuple(f(result), f0, f1, f2);
561 --count;
562
563 BOOST_MATH_INSTRUMENT_VARIABLE(f0);
564 BOOST_MATH_INSTRUMENT_VARIABLE(f1);
565 BOOST_MATH_INSTRUMENT_VARIABLE(f2);
566
567 if (0 == f0)
568 break;
569 if (f1 == 0)
570 {
571 // Oops zero derivative!!!
572 #ifdef BOOST_MATH_INSTRUMENT
573 std::cout << "Second order root iteration, zero derivative found!" << std::endl;
574 #endif
575 detail::handle_zero_derivative(f, last_f0, f0, delta, result, guess, min, max);
576 }
577 else
578 {
579 if (f2 != 0)
580 {
581 delta = Stepper::step(result, f0, f1, f2);
582 if (delta * f1 / f0 < 0)
583 {
584 // Oh dear, we have a problem as Newton and Halley steps
585 // disagree about which way we should move. Probably
586 // there is cancelation error in the calculation of the
587 // Halley step, or else the derivatives are so small
588 // that their values are basically trash. We will move
589 // in the direction indicated by a Newton step, but
590 // by no more than twice the current guess value, otherwise
591 // we can jump way out of bounds if we're not careful.
592 // See https://svn.boost.org/trac/boost/ticket/8314.
593 delta = f0 / f1;
594 if (fabs(delta) > 2 * fabs(guess))
595 delta = (delta < 0 ? -1 : 1) * 2 * fabs(guess);
596 }
597 }
598 else
599 delta = f0 / f1;
600 }
601 #ifdef BOOST_MATH_INSTRUMENT
602 std::cout << "Second order root iteration, delta = " << delta << std::endl;
603 #endif
604 T convergence = fabs(delta / delta2);
605 if ((convergence > 0.8) && (convergence < 2))
606 {
607 // last two steps haven't converged.
608 delta = (delta > 0) ? (result - min) / 2 : (result - max) / 2;
609 if ((result != 0) && (fabs(delta) > result))
610 delta = sign(delta) * fabs(result) * 0.9f; // protect against huge jumps!
611 // reset delta2 so that this branch will *not* be taken on the
612 // next iteration:
613 delta2 = delta * 3;
614 delta1 = delta * 3;
615 BOOST_MATH_INSTRUMENT_VARIABLE(delta);
616 }
617 guess = result;
618 result -= delta;
619 BOOST_MATH_INSTRUMENT_VARIABLE(result);
620
621 // check for out of bounds step:
622 if (result < min)
623 {
624 T diff = ((fabs(min) < 1) && (fabs(result) > 1) && (tools::max_value<T>() / fabs(result) < fabs(min)))
625 ? T(1000)
626 : (fabs(min) < 1) && (fabs(tools::max_value<T>() * min) < fabs(result))
627 ? ((min < 0) != (result < 0)) ? -tools::max_value<T>() : tools::max_value<T>() : T(result / min);
628 if (fabs(diff) < 1)
629 diff = 1 / diff;
630 if (!out_of_bounds_sentry && (diff > 0) && (diff < 3))
631 {
632 // Only a small out of bounds step, lets assume that the result
633 // is probably approximately at min:
634 delta = 0.99f * (guess - min);
635 result = guess - delta;
636 out_of_bounds_sentry = true; // only take this branch once!
637 }
638 else
639 {
640 if (fabs(float_distance(min, max)) < 2)
641 {
642 result = guess = (min + max) / 2;
643 break;
644 }
645 delta = bracket_root_towards_min(f, guess, f0, min, max, count);
646 result = guess - delta;
647 guess = min;
648 continue;
649 }
650 }
651 else if (result > max)
652 {
653 T diff = ((fabs(max) < 1) && (fabs(result) > 1) && (tools::max_value<T>() / fabs(result) < fabs(max))) ? T(1000) : T(result / max);
654 if (fabs(diff) < 1)
655 diff = 1 / diff;
656 if (!out_of_bounds_sentry && (diff > 0) && (diff < 3))
657 {
658 // Only a small out of bounds step, lets assume that the result
659 // is probably approximately at min:
660 delta = 0.99f * (guess - max);
661 result = guess - delta;
662 out_of_bounds_sentry = true; // only take this branch once!
663 }
664 else
665 {
666 if (fabs(float_distance(min, max)) < 2)
667 {
668 result = guess = (min + max) / 2;
669 break;
670 }
671 delta = bracket_root_towards_max(f, guess, f0, min, max, count);
672 result = guess - delta;
673 guess = min;
674 continue;
675 }
676 }
677 // update brackets:
678 if (delta > 0)
679 {
680 max = guess;
681 max_range_f = f0;
682 }
683 else
684 {
685 min = guess;
686 min_range_f = f0;
687 }
688 //
689 // Sanity check that we bracket the root:
690 //
691 if (max_range_f * min_range_f > 0)
692 {
693 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 }
695 } while(count && (fabs(result * factor) < fabs(delta)));
696
697 max_iter -= count;
698
699 #ifdef BOOST_MATH_INSTRUMENT
700 std::cout << "Second order root finder, final iteration count = " << max_iter << std::endl;
701 #endif
702
703 return result;
704 }
705 } // T second_order_root_finder
706
707 template <class F, class T>
halley_iterate(F f,T guess,T min,T max,int digits,boost::uintmax_t & max_iter)708 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 {
710 return detail::second_order_root_finder<detail::halley_step>(f, guess, min, max, digits, max_iter);
711 }
712
713 template <class F, class T>
halley_iterate(F f,T guess,T min,T max,int digits)714 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 {
716 boost::uintmax_t m = (std::numeric_limits<boost::uintmax_t>::max)();
717 return halley_iterate(f, guess, min, max, digits, m);
718 }
719
720 namespace detail {
721
722 struct schroder_stepper
723 {
724 template <class T>
stepboost::math::tools::detail::schroder_stepper725 static T step(const T& x, const T& f0, const T& f1, const T& f2) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(T))
726 {
727 using std::fabs;
728 T ratio = f0 / f1;
729 T delta;
730 if ((x != 0) && (fabs(ratio / x) < 0.1))
731 {
732 delta = ratio + (f2 / (2 * f1)) * ratio * ratio;
733 // check second derivative doesn't over compensate:
734 if (delta * ratio < 0)
735 delta = ratio;
736 }
737 else
738 delta = ratio; // fall back to Newton iteration.
739 return delta;
740 }
741 };
742
743 }
744
745 template <class F, class T>
schroder_iterate(F f,T guess,T min,T max,int digits,boost::uintmax_t & max_iter)746 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 {
748 return detail::second_order_root_finder<detail::schroder_stepper>(f, guess, min, max, digits, max_iter);
749 }
750
751 template <class F, class T>
schroder_iterate(F f,T guess,T min,T max,int digits)752 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 {
754 boost::uintmax_t m = (std::numeric_limits<boost::uintmax_t>::max)();
755 return schroder_iterate(f, guess, min, max, digits, m);
756 }
757 //
758 // These two are the old spelling of this function, retained for backwards compatibility just in case:
759 //
760 template <class F, class T>
schroeder_iterate(F f,T guess,T min,T max,int digits,boost::uintmax_t & max_iter)761 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 {
763 return detail::second_order_root_finder<detail::schroder_stepper>(f, guess, min, max, digits, max_iter);
764 }
765
766 template <class F, class T>
schroeder_iterate(F f,T guess,T min,T max,int digits)767 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 {
769 boost::uintmax_t m = (std::numeric_limits<boost::uintmax_t>::max)();
770 return schroder_iterate(f, guess, min, max, digits, m);
771 }
772
773 #ifndef BOOST_NO_CXX11_AUTO_DECLARATIONS
774 /*
775 * Why do we set the default maximum number of iterations to the number of digits in the type?
776 * Because for double roots, the number of digits increases linearly with the number of iterations,
777 * so this default should recover full precision even in this somewhat pathological case.
778 * For isolated roots, the problem is so rapidly convergent that this doesn't matter at all.
779 */
780 template<class Complex, class F>
complex_newton(F g,Complex guess,int max_iterations=std::numeric_limits<typename Complex::value_type>::digits)781 Complex complex_newton(F g, Complex guess, int max_iterations = std::numeric_limits<typename Complex::value_type>::digits)
782 {
783 typedef typename Complex::value_type Real;
784 using std::norm;
785 using std::abs;
786 using std::max;
787 // z0, z1, and z2 cannot be the same, in case we immediately need to resort to Muller's Method:
788 Complex z0 = guess + Complex(1, 0);
789 Complex z1 = guess + Complex(0, 1);
790 Complex z2 = guess;
791
792 do {
793 auto pair = g(z2);
794 if (norm(pair.second) == 0)
795 {
796 // Muller's method. Notation follows Numerical Recipes, 9.5.2:
797 Complex q = (z2 - z1) / (z1 - z0);
798 auto P0 = g(z0);
799 auto P1 = g(z1);
800 Complex qp1 = static_cast<Complex>(1) + q;
801 Complex A = q * (pair.first - qp1 * P1.first + q * P0.first);
802
803 Complex B = (static_cast<Complex>(2) * q + static_cast<Complex>(1)) * pair.first - qp1 * qp1 * P1.first + q * q * P0.first;
804 Complex C = qp1 * pair.first;
805 Complex rad = sqrt(B * B - static_cast<Complex>(4) * A * C);
806 Complex denom1 = B + rad;
807 Complex denom2 = B - rad;
808 Complex correction = (z1 - z2) * static_cast<Complex>(2) * C;
809 if (norm(denom1) > norm(denom2))
810 {
811 correction /= denom1;
812 }
813 else
814 {
815 correction /= denom2;
816 }
817
818 z0 = z1;
819 z1 = z2;
820 z2 = z2 + correction;
821 }
822 else
823 {
824 z0 = z1;
825 z1 = z2;
826 z2 = z2 - (pair.first / pair.second);
827 }
828
829 // See: https://math.stackexchange.com/questions/3017766/constructing-newton-iteration-converging-to-non-root
830 // If f' is continuous, then convergence of x_n -> x* implies f(x*) = 0.
831 // This condition approximates this convergence condition by requiring three consecutive iterates to be clustered.
832 Real tol = (max)(abs(z2) * std::numeric_limits<Real>::epsilon(), std::numeric_limits<Real>::epsilon());
833 bool real_close = abs(z0.real() - z1.real()) < tol && abs(z0.real() - z2.real()) < tol && abs(z1.real() - z2.real()) < tol;
834 bool imag_close = abs(z0.imag() - z1.imag()) < tol && abs(z0.imag() - z2.imag()) < tol && abs(z1.imag() - z2.imag()) < tol;
835 if (real_close && imag_close)
836 {
837 return z2;
838 }
839
840 } while (max_iterations--);
841
842 // The idea is that if we can get abs(f) < eps, we should, but if we go through all these iterations
843 // and abs(f) < sqrt(eps), then roundoff error simply does not allow that we can evaluate f to < eps
844 // This is somewhat awkward as it isn't scale invariant, but using the Daubechies coefficient example code,
845 // I found this condition generates correct roots, whereas the scale invariant condition discussed here:
846 // https://scicomp.stackexchange.com/questions/30597/defining-a-condition-number-and-termination-criteria-for-newtons-method
847 // allows nonroots to be passed off as roots.
848 auto pair = g(z2);
849 if (abs(pair.first) < sqrt(std::numeric_limits<Real>::epsilon()))
850 {
851 return z2;
852 }
853
854 return { std::numeric_limits<Real>::quiet_NaN(),
855 std::numeric_limits<Real>::quiet_NaN() };
856 }
857 #endif
858
859
860 #if !defined(BOOST_NO_CXX17_IF_CONSTEXPR)
861 // https://stackoverflow.com/questions/48979861/numerically-stable-method-for-solving-quadratic-equations/50065711
862 namespace detail
863 {
864 #if defined(BOOST_GNU_STDLIB) && !defined(_GLIBCXX_USE_C99_MATH_TR1)
fma_workaround(float x,float y,float z)865 inline float fma_workaround(float x, float y, float z) { return ::fmaf(x, y, z); }
fma_workaround(double x,double y,double z)866 inline double fma_workaround(double x, double y, double z) { return ::fma(x, y, z); }
867 #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
fma_workaround(long double x,long double y,long double z)868 inline long double fma_workaround(long double x, long double y, long double z) { return ::fmal(x, y, z); }
869 #endif
870 #endif
871 template<class T>
discriminant(T const & a,T const & b,T const & c)872 inline T discriminant(T const& a, T const& b, T const& c)
873 {
874 T w = 4 * a * c;
875 #if defined(BOOST_GNU_STDLIB) && !defined(_GLIBCXX_USE_C99_MATH_TR1)
876 T e = fma_workaround(-c, 4 * a, w);
877 T f = fma_workaround(b, b, -w);
878 #else
879 T e = std::fma(-c, 4 * a, w);
880 T f = std::fma(b, b, -w);
881 #endif
882 return f + e;
883 }
884
885 template<class T>
quadratic_roots_imp(T const & a,T const & b,T const & c)886 std::pair<T, T> quadratic_roots_imp(T const& a, T const& b, T const& c)
887 {
888 #if defined(BOOST_GNU_STDLIB) && !defined(_GLIBCXX_USE_C99_MATH_TR1)
889 using boost::math::copysign;
890 #else
891 using std::copysign;
892 #endif
893 using std::sqrt;
894 if constexpr (std::is_floating_point<T>::value)
895 {
896 T nan = std::numeric_limits<T>::quiet_NaN();
897 if (a == 0)
898 {
899 if (b == 0 && c != 0)
900 {
901 return std::pair<T, T>(nan, nan);
902 }
903 else if (b == 0 && c == 0)
904 {
905 return std::pair<T, T>(0, 0);
906 }
907 return std::pair<T, T>(-c / b, -c / b);
908 }
909 if (b == 0)
910 {
911 T x0_sq = -c / a;
912 if (x0_sq < 0) {
913 return std::pair<T, T>(nan, nan);
914 }
915 T x0 = sqrt(x0_sq);
916 return std::pair<T, T>(-x0, x0);
917 }
918 T discriminant = detail::discriminant(a, b, c);
919 // Is there a sane way to flush very small negative values to zero?
920 // If there is I don't know of it.
921 if (discriminant < 0)
922 {
923 return std::pair<T, T>(nan, nan);
924 }
925 T q = -(b + copysign(sqrt(discriminant), b)) / T(2);
926 T x0 = q / a;
927 T x1 = c / q;
928 if (x0 < x1)
929 {
930 return std::pair<T, T>(x0, x1);
931 }
932 return std::pair<T, T>(x1, x0);
933 }
934 else if constexpr (boost::math::tools::is_complex_type<T>::value)
935 {
936 typename T::value_type nan = std::numeric_limits<typename T::value_type>::quiet_NaN();
937 if (a.real() == 0 && a.imag() == 0)
938 {
939 using std::norm;
940 if (b.real() == 0 && b.imag() && norm(c) != 0)
941 {
942 return std::pair<T, T>({ nan, nan }, { nan, nan });
943 }
944 else if (b.real() == 0 && b.imag() && c.real() == 0 && c.imag() == 0)
945 {
946 return std::pair<T, T>({ 0,0 }, { 0,0 });
947 }
948 return std::pair<T, T>(-c / b, -c / b);
949 }
950 if (b.real() == 0 && b.imag() == 0)
951 {
952 T x0_sq = -c / a;
953 T x0 = sqrt(x0_sq);
954 return std::pair<T, T>(-x0, x0);
955 }
956 // There's no fma for complex types:
957 T discriminant = b * b - T(4) * a * c;
958 T q = -(b + sqrt(discriminant)) / T(2);
959 return std::pair<T, T>(q / a, c / q);
960 }
961 else // Most likely the type is a boost.multiprecision.
962 { //There is no fma for multiprecision, and in addition it doesn't seem to be useful, so revert to the naive computation.
963 T nan = std::numeric_limits<T>::quiet_NaN();
964 if (a == 0)
965 {
966 if (b == 0 && c != 0)
967 {
968 return std::pair<T, T>(nan, nan);
969 }
970 else if (b == 0 && c == 0)
971 {
972 return std::pair<T, T>(0, 0);
973 }
974 return std::pair<T, T>(-c / b, -c / b);
975 }
976 if (b == 0)
977 {
978 T x0_sq = -c / a;
979 if (x0_sq < 0) {
980 return std::pair<T, T>(nan, nan);
981 }
982 T x0 = sqrt(x0_sq);
983 return std::pair<T, T>(-x0, x0);
984 }
985 T discriminant = b * b - 4 * a * c;
986 if (discriminant < 0)
987 {
988 return std::pair<T, T>(nan, nan);
989 }
990 T q = -(b + copysign(sqrt(discriminant), b)) / T(2);
991 T x0 = q / a;
992 T x1 = c / q;
993 if (x0 < x1)
994 {
995 return std::pair<T, T>(x0, x1);
996 }
997 return std::pair<T, T>(x1, x0);
998 }
999 }
1000 } // namespace detail
1001
1002 template<class T1, class T2 = T1, class T3 = T1>
quadratic_roots(T1 const & a,T2 const & b,T3 const & c)1003 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)
1004 {
1005 typedef typename tools::promote_args<T1, T2, T3>::type value_type;
1006 return detail::quadratic_roots_imp(static_cast<value_type>(a), static_cast<value_type>(b), static_cast<value_type>(c));
1007 }
1008
1009 #endif
1010
1011 } // namespace tools
1012 } // namespace math
1013 } // namespace boost
1014
1015 #endif // BOOST_MATH_TOOLS_NEWTON_SOLVER_HPP
1016