5#ifndef LINE_UTIL_ROOTFIND_H
6#define LINE_UTIL_ROOTFIND_H
69template <
class T,
class F>
93 if ((flo > zero) == (fhi > zero))
94 throw InputError(
"root_bisect: the bracket endpoints do not straddle a root");
96 for (
unsigned it = 0; it < maxiter; ++it) {
98 const T mid = (lo + hi) / two;
107 if ((fm > zero) == (flo > zero)) {
114 if (T(hi - lo) <= tol)
break;
116 const T mid = (lo + hi) / two;
129template <
class T,
class F>
156 if ((fa > zero) == (fb > zero))
157 throw InputError(
"root_brent: the bracket endpoints do not straddle a root");
171 bool used_bisect =
true;
173 for (
unsigned it = 0; it < maxiter; ++it) {
175 if ((fb > zero) == (fc > zero)) {
189 const T m = half * T(c - b);
190 if (
num_abs(T(m)) <= tol || fb == zero)
break;
192 bool interpolate =
false;
193 T s = zero, p = zero, q = zero;
200 const T qq = fa / fc;
201 const T rr = fb / fc;
210 const T lim1 = three * m * q -
num_abs(T(tol * q));
211 const T lim2 =
num_abs(T(e * q));
212 interpolate = two * p < (lim1 < lim2 ? lim1 : lim2);
214 e = interpolate ? d : m;
215 d = interpolate ? p / q : m;
216 used_bisect = !interpolate;
224 b += (m > zero ? tol : T(-tol));
246template <
class T,
class F,
class DF>
254 for (
unsigned it = 0; it < maxiter; ++it) {
264 if (dfx == zero)
throw NumericError(
"root_newton: the derivative vanished at an iterate");
265 const T step = fx / dfx;
284template <
class T,
class F,
class DF>
286 unsigned maxiter = 200) {
289 T lo = a0 < b0 ? a0 : b0;
290 T hi = a0 < b0 ? b0 : a0;
309 if ((flo > zero) == (fhi > zero))
310 throw InputError(
"root_newton_safe: the bracket endpoints do not straddle a root");
312 T x = (lo + hi) / two;
313 for (
unsigned it = 0; it < maxiter; ++it) {
323 if ((fx > zero) == (flo > zero)) {
330 const T width = T(hi - lo);
331 if (width <= tol)
break;
334 bool take_newton =
false;
336 if (!(dfx == zero)) {
338 take_newton = xn > lo && xn < hi;
340 x = take_newton ? xn : (lo + hi) / two;
356template <
class T,
class F>
365 for (
unsigned it = 0; it < maxdoubling; ++it) {
367 if (fb == zero || (fb > zero) != (fa > zero))
return;
370 throw NumericError(
"bracket_expand: no sign change found while expanding the bracket");
NumericError(const std::string &what)
The exception types the port throws.
RootResult< T > root_newton_safe(F f, DF df, const T &a0, const T &b0, const T &tol, unsigned maxiter=200)
Newton safeguarded by a bracket with a sign change: the Newton step is used only when it stays inside...
RootResult< T > root_bisect(F f, const T &a, const T &b, const T &tol, unsigned maxiter=200)
Bisection on a bracket with a sign change.
RootResult< T > root_brent(F f, const T &a0, const T &b0, const T &tol, unsigned maxiter=200)
Brent's method on a bracket with a sign change.
void bracket_expand(F f, const T &a, T &b, unsigned maxdoubling=200)
Expand a bracket to the right until f changes sign, doubling the upper end.
RootResult< T > root_newton(F f, DF df, const T &x0, const T &tol, unsigned maxiter=200)
Plain Newton from a starting point.
Number-type abstraction for the templated API port.
Outcome of a scalar solve.
bool converged
tolerance was met before the iteration cap
T root
best estimate of the root
T bracket_width
final |b - a|, zero for the unbracketed Newton
unsigned iterations
iterations actually performed