41 const Real tolerance = 5 * std::numeric_limits<Real>::epsilon();
42 Real c = a - (fa / (fb - fa)) * (b - a);
43 if (c <= a + std::fabs(a) * tolerance || c >= b - std::fabs(b) * tolerance)
44 return a + (b - a) / 2;
51 Real B =
safeDivide(fb - fa, b - a, std::numeric_limits<Real>::max());
52 Real A =
safeDivide(fd - fb, d - b, std::numeric_limits<Real>::max());
56 Real c = (std::signbit(A) == std::signbit(fa)) ? a : b;
57 for (
int i = 0; i < steps; ++i)
58 c -=
safeDivide(fa + (B + A * (c - b)) * (c - a), B + A * (2 * c - a - b), 1 + c - a);
59 if (!(c > a && c < b))
65Real
inverseCubicStep(Real a, Real b, Real d, Real e, Real fa, Real fb, Real fd, Real fe)
67 Real q11 = (d - e) * fd / (fe - fd);
68 Real q21 = (b - d) * fb / (fd - fb);
69 Real q31 = (a - b) * fa / (fb - fa);
70 Real d21 = (b - d) * fd / (fd - fb);
71 Real d31 = (a - b) * fb / (fb - fa);
72 Real q22 = (d21 - q11) * fb / (fe - fb);
73 Real q32 = (d31 - q21) * fa / (fd - fa);
74 Real d32 = (d31 - q21) * fd / (fd - fa);
75 Real q33 = (d32 - q22) * fa / (fe - fa);
76 Real c = q31 + q32 + q33 + a;
77 if (!(c > a && c < b))
98std::pair<Real, Real>
toms748(
const F &f, Real a, Real b, Real fa, Real fb,
int maxIterations = 200)
108 if (std::signbit(fa) == std::signbit(fb))
109 throw std::invalid_argument(
"toms748: the root is not bracketed");
111 Real d = 0, fd = 0, e = 0, fe = 0;
112 int count = maxIterations;
114 auto bracket = [&f, &a, &b, &fa, &fb, &d, &fd](Real c) {
115 const Real tolerance = 2 * std::numeric_limits<Real>::epsilon();
116 if (b - a < 2 * tolerance * std::fabs(a))
118 else if (c <= a + std::fabs(a) * tolerance)
119 c = a + std::fabs(a) * tolerance;
120 else if (c >= b - std::fabs(b) * tolerance)
121 c = b - std::fabs(b) * tolerance;
122 if (!(c > a && c < b))
130 if (std::signbit(fa) != std::signbit(fc)) {
152 const Real minDifference = 32 * std::numeric_limits<Real>::min();
153 auto distinct = [&] {
154 return std::fabs(fa - fb) >= minDifference && std::fabs(fa - fd) >= minDifference &&
155 std::fabs(fa - fe) >= minDifference && std::fabs(fb - fd) >= minDifference &&
156 std::fabs(fb - fe) >= minDifference && std::fabs(fd - fe) >= minDifference;
159 const Real a0 = a, b0 = b;
175 const bool aIsCloser = std::fabs(fa) < std::fabs(fb);
176 const Real u = aIsCloser ? a : b, fu = aIsCloser ? fa : fb;
177 c = u - 2 * (fu / (fb - fa)) * (b - a);
178 if (std::fabs(c - u) > (b - a) / 2)
187 if (b - a < (b0 - a0) / 2)
191 bracket(a + (b - a) / 2);
205Real
findRoot(
const F &f, std::type_identity_t<Real> a, std::type_identity_t<Real> b,
int maxIterations = 200)
207 auto [lo, hi] = toms748<Real>(f, a, b, f(a), f(b), maxIterations);
208 return lo + (hi - lo) / 2;
222 long double funTol = 1e-10,
long double stepTol = 1e-6)
227 static constexpr int MAX_ITER = 1e5;
228 static constexpr double MAX_STEP = 10;
230 double step = stepTol + 1;
232 double fun = y.first;
233 double grad = y.second;
234 if (!std::isfinite(root) || !std::isfinite(fun) || !std::isfinite(grad))
240 double oldRoot = root;
242 double newtonStep = fun / grad;
243 if (!std::isfinite(newtonStep))
245 step = std::min(MAX_STEP, std::max(-MAX_STEP, newtonStep));
246 bool accepted =
false;
247 for (
int backtrack = 0; backtrack < 64; ++backtrack) {
248 root = oldRoot - alpha * step;
249 if (!std::isfinite(root)) {
259 std::fabs(fun) <= std::fabs(oldFun)) {
270 double diffX = std::fabs(root - oldRoot);
271 double relDiffX = std::fabs(diffX / oldRoot);
272 if (std::min(diffX, relDiffX) < stepTol) {
273 double diffY = fun - oldFun;
274 double relDiffY = std::fabs(diffY / oldFun);
275 if (std::min(std::fabs(fun), relDiffY) < funTol)
278 }
while (++iter < MAX_ITER);
293 long double funTol = 1e-10,
long double stepTol = 1e-6)
298 static constexpr int MAX_ITER = 1e5;
299 static constexpr double MAX_STEP = 10;
301 double step = stepTol + 1;
302 auto [f, fx, fxx] = funPtr(root);
307 double oldRoot = root;
309 double numerator = 2 * f * fx;
310 double denominator = 2 * fx * fx - f * fxx;
311 step = std::min(MAX_STEP, std::max(-MAX_STEP, numerator / denominator));
313 root = oldRoot - alpha * step;
314 std::tie(f, fx, fxx) = funPtr(root);
320 double diffX = std::fabs(root - oldRoot);
321 double relDiffX = std::fabs(diffX / oldRoot);
322 if (std::min(diffX, relDiffX) < stepTol) {
323 double diffY = f - oldFun;
324 double relDiffY = std::fabs(diffY / oldFun);
325 if (std::min(std::fabs(f), relDiffY) < funTol)
328 }
while (++iter < MAX_ITER);
348 const std::function<std::tuple<DoublePair, DoublePair>(
DoublePair)> &gradPtr,
349 DoublePair &root,
long double funTol,
long double stepTol)
354 static constexpr int MAX_ITER = 1e5;
355 static constexpr double MAX_STEP = 10;
360 double fun1 = fun.first;
361 double fun2 = fun.second;
362 double error = std::max(std::fabs(fun1), std::fabs(fun2));
366 auto [grad1, grad2] = gradPtr(root);
371 double oldError = error;
372 double det = grad1.first * grad2.second - grad1.second * grad2.first;
373 step1 = std::min(MAX_STEP, std::max(-MAX_STEP, (grad2.second * fun1 - grad1.second * fun2) / det));
374 step2 = std::min(MAX_STEP, std::max(-MAX_STEP, (-grad2.first * fun1 + grad1.first * fun2) / det));
376 root.first = oldRoot.first - alpha * step1;
377 root.second = oldRoot.second - alpha * step2;
381 error = std::max(std::fabs(fun1), std::fabs(fun2));
384 std::tie(grad1, grad2) = gradPtr(root);
385 det = grad1.first * grad2.second - grad1.second * grad2.first;
390 double diffX1 = std::fabs(root.first - oldRoot.first);
391 double diffX2 = std::fabs(root.second - oldRoot.second);
392 double diffX = std::max(diffX1, diffX2);
393 double relDiffX1 = std::fabs(diffX1 / oldRoot.first);
394 double relDiffX2 = std::fabs(diffX2 / oldRoot.second);
395 double relDiffX = std::max(relDiffX1, relDiffX2);
396 if (std::min(diffX, relDiffX) < stepTol) {
397 double diffY1 = fun1 - oldFun.first;
398 double diffY2 = fun2 - oldFun.second;
399 double relDiffY1 = std::fabs(diffY1 / oldFun.first);
400 double relDiffY2 = std::fabs(diffY2 / oldFun.second);
401 double relDiffY = std::max(relDiffY1, relDiffY2);
402 if (std::min(std::max(std::fabs(fun1), std::fabs(fun2)), relDiffY) < funTol)
405 }
while (++iter < MAX_ITER);
Real inverseCubicStep(Real a, Real b, Real d, Real e, Real fa, Real fb, Real fd, Real fe)
Definition roots.hpp:65
bool findRootNewtonFirstOrder(const std::function< DoublePair(RealType)> &funPtr, RealType &root, long double funTol=1e-10, long double stepTol=1e-6)
Newton's root-finding procedure, using first derivative.
Definition roots.hpp:221
bool findRootNewtonSecondOrder(const std::function< DoubleTriplet(RealType)> &funPtr, RealType &root, long double funTol=1e-10, long double stepTol=1e-6)
Newton's root-finding procedure, using first and second derivatives.
Definition roots.hpp:292
bool findRootNewtonFirstOrder2d(const std::function< DoublePair(DoublePair)> &funPtr, const std::function< std::tuple< DoublePair, DoublePair >(DoublePair)> &gradPtr, DoublePair &root, long double funTol=1e-10, long double stepTol=1e-6)
Newton's root-finding procedure for 2 functions of 2 parameters, using Jacobian matrix.
Definition roots.hpp:347
std::pair< Real, Real > toms748(const F &f, Real a, Real b, Real fa, Real fb, int maxIterations=200)
Bracketing root finder of Alefeld, Potra and Shi (ACM TOMS algorithm 748): inverse cubic and Newton-q...
Definition roots.hpp:98