suanPan
🧮 An Open Source, Parallel and Heterogeneous Finite Element Analysis Framework
Loading...
Searching...
No Matches
brent.hpp
Go to the documentation of this file.
1/*******************************************************************************
2 * Copyright (C) 2017-2026 Theodore Chang
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 ******************************************************************************/
17
18#ifndef BRENT_HPP
19#define BRENT_HPP
20
21#include <suanPan.h>
22
46template<std::floating_point T, std::invocable<T> F> T brent(F&& func, const T x1, const T x2, const T tol) {
47 static constexpr auto eps = std::numeric_limits<T>::epsilon();
48 auto a = x1, b = x2, c = x2;
49 T fa = func(a), fb = func(b), fc = fb;
50
51 T d{}, e{}, p{}, q{};
52
53 auto counter = 0u;
54 while(true) {
55 ++counter;
56
57 if(fb * fc > T(0)) {
58 c = a;
59 fc = fa;
60 e = d = b - a;
61 }
62 if(std::fabs(fc) < std::fabs(fb)) {
63 a = b;
64 b = c;
65 c = a;
66 fa = fb;
67 fb = fc;
68 fc = fa;
69 }
70 const auto comp_tol = T(2) * eps * std::fabs(b) + T(.5) * tol;
71 const auto xm = T(.5) * (c - b);
72 if(std::fabs(xm) <= comp_tol || std::fabs(fb) < tol) {
73 suanpan_debug("Brent's method initial guess {:.5E} with {} iterations.\n", b, counter);
74 return b;
75 }
76 if(std::fabs(e) >= comp_tol && std::fabs(fa) > std::fabs(fb)) {
77 const auto s = fb / fa;
78 if(a == c) {
79 p = T(2) * xm * s;
80 q = T(1) - s;
81 }
82 else {
83 q = fa / fc;
84 const auto r = fb / fc;
85 p = s * (T(2) * xm * q * (q - r) - (b - a) * (r - T(1)));
86 q = (q - T(1)) * (r - T(1)) * (s - T(1));
87 }
88 if(p > T(0)) q = -q;
89 else p = std::fabs(p);
90 if(T(2) * p < std::min(T(3) * xm * q - std::fabs(comp_tol * q), std::fabs(e * q))) {
91 e = d;
92 d = p / q;
93 }
94 else e = d = xm;
95 }
96 else e = d = xm;
97 a = b;
98 fa = fb;
99 const auto dd = xm >= T(0) ? comp_tol : -comp_tol;
100 fb = func(b += std::fabs(d) > comp_tol ? d : dd);
101 }
102}
103
104#endif
105
T brent(F &&func, const T x1, const T x2, const T tol)
Implements Brent's method for finding a root of a function within a given interval.
Definition brent.hpp:46
#define suanpan_debug(...)
Definition suanPan.h:347