rustyqlib/core/solvers/
secant.rs1use super::solver_1d::{Root, Solver1d};
5
6pub fn secant(cfg: &Solver1d, f: impl Fn(f64) -> f64, x0: f64, x1: f64) -> Root {
8 let (mut x_prev, mut x) = (x0, x1);
9 let mut f_prev = f(x_prev);
10 if f_prev.abs() <= cfg.tol {
11 return Root { x: x_prev, iterations: 0, converged: true };
12 }
13 for i in 0..cfg.max_iter {
14 let fx = f(x);
15 if fx.abs() <= cfg.tol {
16 return Root { x, iterations: i, converged: true };
17 }
18 let slope = (fx - f_prev) / (x - x_prev);
19 if slope == 0.0 || !slope.is_finite() {
20 return Root { x, iterations: i, converged: false };
21 }
22 (x_prev, f_prev) = (x, fx);
23 x -= fx / slope;
24 }
25 Root { x, iterations: cfg.max_iter, converged: f(x).abs() <= cfg.tol }
26}
27
28#[cfg(test)]
29mod tests {
30 use super::*;
31
32 #[test]
33 fn finds_sqrt_two() {
34 let r = secant(&Solver1d::default(), |x| x * x - 2.0, 1.0, 2.0);
35 assert!(r.converged && (r.x - std::f64::consts::SQRT_2).abs() < 1e-12, "{r:?}");
36 }
37}