in include/maths/common/CSolvers.h [508:608]
static bool brent(double& a,
double& b,
double fa,
double fb,
const F& f,
std::size_t& maxIterations,
const EQUAL& equal,
double& bestGuess) {
std::size_t n = std::max(maxIterations, std::size_t{1});
if (fa == 0.0) {
// Root at left bracket.
bestGuess = b = a;
maxIterations -= n;
return true;
}
if (fb == 0.0) {
// Root at right bracket.
bestGuess = a = b;
maxIterations -= n;
return true;
}
if (std::signbit(fa) == std::signbit(fb)) {
// Not bracketed.
maxIterations -= n;
return false;
}
if (std::fabs(fa) < std::fabs(fb)) {
std::swap(a, b);
std::swap(fa, fb);
}
bool bisected = true;
double c = a;
double fc = fa;
double d = std::numeric_limits<double>::max();
do {
double s;
bool canUseInverseQuadratic = ((fa != fc) && (fb != fc));
bool canUseSecant = (fa != fb);
if (canUseInverseQuadratic || canUseSecant) {
s = canUseInverseQuadratic
? inverseQuadraticInterpolate(a, b, c, fa, fb, fc)
: secantInterpolate(a, b, fa, fb);
double e = (3.0 * a + b) / 4.0;
if ((!(((s > e) && (s < b)) || ((s < e) && (s > b)))) ||
(bisected &&
((std::fabs(s - b) >= std::fabs(b - c) / 2.0) || equal(b, c))) ||
(!bisected &&
((std::fabs(s - b) >= std::fabs(c - d) / 2.0) || equal(c, d)))) {
// Use bisection.
s = bisect(a, b);
bisected = true;
} else {
bisected = false;
}
} else {
s = bisect(a, b);
bisected = true;
}
double fs = f(s);
shift(d, c, b);
fc = fb;
if (fs == 0.0) {
// Root at s.
bestGuess = a = b = s;
maxIterations -= (n - 1);
return true;
}
if (std::signbit(fa) == std::signbit(fs)) {
a = s;
fa = fs;
} else {
b = s;
fb = fs;
}
if (std::fabs(fa) < std::fabs(fb)) {
std::swap(a, b);
std::swap(fa, fb);
}
} while (--n > 0 && !equal(a, b));
if (b < a) {
std::swap(a, b);
std::swap(fa, fb);
}
bestGuess = (fa != fc) && (fb != fc)
? inverseQuadraticInterpolate(a, b, c, fa, fb, fc)
: (fa != fb ? secantInterpolate(a, b, fa, fb) : bisect(a, b));
bestGuess = std::min(std::max(a, bestGuess), b);
maxIterations -= n;
return true;
}