numerics 0.1.0
Loading...
Searching...
No Matches
roots.cpp
Go to the documentation of this file.
1/// @file roots.cpp
2#include "analysis/roots.hpp"
3#include <cmath>
4#include <stdexcept>
5
6namespace num {
7
8RootResult bisection(ScalarFn f, real a, real b, real tol, idx max_iter) {
9 real fa = f(a), fb = f(b);
10 if (fa * fb > 0.0)
11 throw std::invalid_argument(
12 "bisection: f(a) and f(b) must have opposite signs");
13
14 for (idx i = 0; i < max_iter; ++i) {
15 real mid = 0.5 * (a + b);
16 real fm = f(mid);
17 if (std::abs(fm) < tol || 0.5 * (b - a) < tol)
18 return {mid, i + 1, std::abs(fm), true};
19 if (fa * fm < 0.0) {
20 b = mid;
21 fb = fm;
22 } else {
23 a = mid;
24 fa = fm;
25 }
26 }
27 real mid = 0.5 * (a + b);
28 return {mid, max_iter, std::abs(f(mid)), false};
29}
30
31RootResult newton(ScalarFn f, ScalarFn df, real x0, real tol, idx max_iter) {
32 real x = x0;
33 for (idx i = 0; i < max_iter; ++i) {
34 real fx = f(x);
35 if (std::abs(fx) < tol)
36 return {x, i + 1, std::abs(fx), true};
37 real dfx = df(x);
38 if (std::abs(dfx) < 1e-14)
39 return {x, i + 1, std::abs(fx), false}; // near-zero derivative
40 x -= fx / dfx;
41 }
42 return {x, max_iter, std::abs(f(x)), false};
43}
44
45RootResult secant(ScalarFn f, real x0, real x1, real tol, idx max_iter) {
46 real f0 = f(x0), f1 = f(x1);
47 for (idx i = 0; i < max_iter; ++i) {
48 if (std::abs(f1) < tol)
49 return {x1, i + 1, std::abs(f1), true};
50 real df = f1 - f0;
51 if (std::abs(df) < 1e-14)
52 return {x1, i + 1, std::abs(f1), false}; // stagnation
53 real x2 = x1 - f1 * (x1 - x0) / df;
54 x0 = x1;
55 f0 = f1;
56 x1 = x2;
57 f1 = f(x1);
58 }
59 return {x1, max_iter, std::abs(f1), false};
60}
61
62RootResult brent(ScalarFn f, real a, real b, real tol, idx max_iter) {
63 real fa = f(a), fb = f(b);
64 if (fa * fb > 0.0)
65 throw std::invalid_argument(
66 "brent: f(a) and f(b) must have opposite signs");
67
68 // c is the point such that [b,c] is always a valid bracket
69 real c = a, fc = fa;
70 real d = b - a, e = d;
71
72 for (idx i = 0; i < max_iter; ++i) {
73 // ensure b is the best estimate
74 if (fb * fc > 0.0) {
75 c = a;
76 fc = fa;
77 d = e = b - a;
78 }
79 if (std::abs(fc) < std::abs(fb)) {
80 a = b;
81 fa = fb;
82 b = c;
83 fb = fc;
84 c = a;
85 fc = fa;
86 }
87
88 real tol1 = 2.0 * 1e-15 * std::abs(b) + 0.5 * tol;
89 real mid = 0.5 * (c - b);
90
91 if (std::abs(mid) <= tol1 || std::abs(fb) < tol)
92 return {b, i + 1, std::abs(fb), true};
93
94 if (std::abs(e) >= tol1 && std::abs(fa) > std::abs(fb)) {
95 // attempt interpolation
96 real s = fb / fa;
97 real p, q;
98 if (a == c) {
99 // secant step
100 p = 2.0 * mid * s;
101 q = 1.0 - s;
102 } else {
103 // inverse quadratic interpolation
104 real r = fb / fc;
105 real t = fa / fc;
106 p = s * (2.0 * mid * t * (t - r) - (b - a) * (r - 1.0));
107 q = (t - 1.0) * (r - 1.0) * (s - 1.0);
108 }
109 if (p > 0.0)
110 q = -q;
111 else
112 p = -p;
113
114 // accept interpolation only if step is smaller than previous
115 real e_prev = e;
116 if (2.0 * p < std::min(3.0 * mid * q - std::abs(tol1 * q),
117 std::abs(e_prev * q))) {
118 e = d;
119 d = p / q;
120 } else {
121 d = mid;
122 e = mid;
123 }
124 } else {
125 d = mid;
126 e = mid;
127 }
128
129 a = b;
130 fa = fb;
131 b += (std::abs(d) > tol1) ? d : (mid > 0.0 ? tol1 : -tol1);
132 fb = f(b);
133 }
134 return {b, max_iter, std::abs(fb), false};
135}
136
137} // namespace num
RootResult secant(ScalarFn f, real x0, real x1, real tol=1e-10, idx max_iter=1000)
Secant method (Newton without derivative)
Definition roots.cpp:45
double real
Definition types.hpp:10
RootResult bisection(ScalarFn f, real a, real b, real tol=1e-10, idx max_iter=1000)
Bisection method.
Definition roots.cpp:8
RootResult brent(ScalarFn f, real a, real b, real tol=1e-10, idx max_iter=1000)
Brent's method (bisection + secant + inverse quadratic interpolation)
Definition roots.cpp:62
std::size_t idx
Definition types.hpp:11
RootResult newton(ScalarFn f, ScalarFn df, real x0, real tol=1e-10, idx max_iter=1000)
Newton-Raphson method.
Definition roots.cpp:31
constexpr real e
Definition math.hpp:43
std::function< real(real)> ScalarFn
Real-valued scalar function f(x)
Definition types.hpp:11
Root-finding methods for scalar equations f(x) = 0.