pub trait Rootfinder<F>
where
F: Fn(f64) -> f64,
{
const MAX_ITERATIONS: i32 = 1000;
fn value(&self, x: f64) -> f64;
fn derivative(&self, x: f64) -> f64;
fn solve_impl(&mut self) -> f64;
fn solve(&mut self) -> f64;
}
#[derive(Debug, Clone, Copy)]
pub struct RootfinderData {
pub root: f64,
pub stepsize: f64,
pub accuracy: f64,
pub interval: (f64, f64),
pub interval_enforced: bool,
pub(crate) x_min: f64,
pub(crate) x_max: f64,
pub(crate) y_min: f64,
pub(crate) y_max: f64,
pub(crate) iteration_count: i32,
}
impl Default for RootfinderData {
fn default() -> Self {
Self {
interval: (f64::MIN, f64::MAX),
interval_enforced: true,
stepsize: 1e-6,
accuracy: f64::EPSILON.sqrt(),
root: 0.0,
x_min: f64::MIN,
x_max: f64::MAX,
y_min: f64::MIN,
y_max: f64::MAX,
iteration_count: 0,
}
}
}
impl RootfinderData {
pub fn new(
accuracy: f64,
stepsize: f64,
lower_bound: f64,
upper_bound: f64,
interval_enforced: bool,
) -> Self {
Self {
interval: (lower_bound, upper_bound),
interval_enforced,
stepsize,
accuracy,
root: 0.0,
x_min: f64::MIN,
x_max: f64::MAX,
y_min: f64::MIN,
y_max: f64::MAX,
iteration_count: 0,
}
}
pub(crate) fn enforce_bounds(&self, x: f64) -> f64 {
if self.interval_enforced && x < self.interval.0 {
return self.interval.0;
}
if self.interval_enforced && x > self.interval.1 {
return self.interval.1;
}
x
}
#[inline]
pub(crate) fn increment_evaluation_count(&mut self) {
self.iteration_count += 1;
}
#[inline]
pub(crate) fn nrsign(a: f64, b: f64) -> f64 {
let t1 = if a >= 0.0 { a } else { -a };
let t2 = if a >= 0.0 { -a } else { a };
if b >= 0.0 {
t1
} else {
t2
}
}
pub(crate) fn close(x: f64, y: f64) -> bool {
if x == y {
return true;
}
let n = 42;
let diff = f64::abs(x - y);
let tolerance = n as f64 * f64::EPSILON;
if x * y == 0.0 {
return diff < f64::powi(tolerance, 2);
}
diff <= tolerance * f64::abs(x) && diff <= tolerance * f64::abs(y)
}
#[allow(dead_code)]
pub(crate) fn close_enough(x: f64, y: f64) -> bool {
if x == y {
return true;
}
let n = 42;
let diff = f64::abs(x - y);
let tolerance = n as f64 * f64::EPSILON;
if x * y == 0.0 {
return diff < f64::powi(tolerance, 2);
}
diff <= tolerance * f64::abs(x) || diff <= tolerance * f64::abs(y)
}
}