use crate::{base_float::BaseFloat, dim1_func::Dim1Func};
use core_float::core_float_traits::CoreFloat;
use super::Dim1Solver;
pub struct BisectionSolver<T> {
search_range: [T; 2],
error_tolerance: T,
}
impl<T: CoreFloat> BisectionSolver<T> {
pub fn new(search_range: [T; 2], error_tolerance: T) -> Self {
assert!(search_range[0] < search_range[1]);
assert!(error_tolerance > T::EPSILON);
Self {
search_range,
error_tolerance,
}
}
}
impl<T: BaseFloat> Dim1Solver<T> for BisectionSolver<T> {
fn solve(&self, func: &impl Dim1Func<T>) -> Option<T> {
let (mut a, mut b) = (self.search_range[0], self.search_range[1]);
assert!(func.eval(a).sig_ne(func.eval(b)));
let mut iter_num: usize = 0;
while (b - a) > self.error_tolerance.double() {
let c = (b + a).half();
let fc = func.eval(c);
if fc == T::ZERO {
break;
}
if func.eval(a).sig_ne(fc) {
b = c;
} else {
debug_assert!(func.eval(b).sig_ne(fc));
a = c;
}
iter_num += 1;
}
log::info!("Bisection solve, iteration number = {}", iter_num);
Some((b + a).half())
}
}