refactor newton's method
This commit is contained in:
parent
7dc7167a57
commit
50892ed4b5
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use crate::egui_app::AppSettings;
|
use crate::egui_app::AppSettings;
|
||||||
use crate::function_output::FunctionOutput;
|
use crate::function_output::FunctionOutput;
|
||||||
use crate::misc::{dyn_iter, newtons_method, resolution_helper, step_helper, SteppedVector};
|
use crate::misc::{dyn_iter, newtons_method_helper, resolution_helper, step_helper, SteppedVector};
|
||||||
use crate::parsing::BackingFunction;
|
use crate::parsing::BackingFunction;
|
||||||
use eframe::{egui, epaint};
|
use eframe::{egui, epaint};
|
||||||
use egui::{
|
use egui::{
|
||||||
@ -133,14 +133,14 @@ impl FunctionEntry {
|
|||||||
|
|
||||||
fn newtons_method_helper(&self, threshold: f64, derivative_level: usize) -> Option<Vec<Value>> {
|
fn newtons_method_helper(&self, threshold: f64, derivative_level: usize) -> Option<Vec<Value>> {
|
||||||
let newtons_method_output: Vec<f64> = match derivative_level {
|
let newtons_method_output: Vec<f64> = match derivative_level {
|
||||||
0 => newtons_method(
|
0 => newtons_method_helper(
|
||||||
threshold,
|
threshold,
|
||||||
self.min_x..self.max_x,
|
self.min_x..self.max_x,
|
||||||
self.output.back.to_owned().unwrap(),
|
self.output.back.to_owned().unwrap(),
|
||||||
&|x: f64| self.function.get(x),
|
&|x: f64| self.function.get(x),
|
||||||
&|x: f64| self.function.get_derivative_1(x),
|
&|x: f64| self.function.get_derivative_1(x),
|
||||||
),
|
),
|
||||||
1 => newtons_method(
|
1 => newtons_method_helper(
|
||||||
threshold,
|
threshold,
|
||||||
self.min_x..self.max_x,
|
self.min_x..self.max_x,
|
||||||
self.output.derivative.to_owned().unwrap(),
|
self.output.derivative.to_owned().unwrap(),
|
||||||
|
|||||||
63
src/misc.rs
63
src/misc.rs
@ -173,14 +173,14 @@ pub fn decimal_round(x: f64, n: usize) -> f64 {
|
|||||||
// off after the `n`th decimal place
|
// off after the `n`th decimal place
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements newton's method of finding roots.
|
/// Helper that assists with using newton's method of finding roots, iterating
|
||||||
/// `threshold` is the target accuracy threshold
|
/// over data `data` `threshold` is the target accuracy threshold
|
||||||
/// `range` is the range of valid x values (used to stop calculation when the
|
/// `range` is the range of valid x values (used to stop calculation when the
|
||||||
/// point won't display anyways) `data` is the data to iterate over (a Vector of
|
/// point won't display anyways) `data` is the data to iterate over (a Vector of
|
||||||
/// egui's `Value` struct) `f` is f(x)
|
/// egui's `Value` struct) `f` is f(x)
|
||||||
/// `f_1` is f'(x) aka the derivative of f(x)
|
/// `f_1` is f'(x) aka the derivative of f(x)
|
||||||
/// The function returns a Vector of `x` values where roots occur
|
/// The function returns a Vector of `x` values where roots occur
|
||||||
pub fn newtons_method(
|
pub fn newtons_method_helper(
|
||||||
threshold: f64, range: std::ops::Range<f64>, data: Vec<EguiValue>, f: &dyn Fn(f64) -> f64,
|
threshold: f64, range: std::ops::Range<f64>, data: Vec<EguiValue>, f: &dyn Fn(f64) -> f64,
|
||||||
f_1: &dyn Fn(f64) -> f64,
|
f_1: &dyn Fn(f64) -> f64,
|
||||||
) -> Vec<f64> {
|
) -> Vec<f64> {
|
||||||
@ -190,34 +190,45 @@ pub fn newtons_method(
|
|||||||
.filter(|(prev, curr)| prev.y.signum() != curr.y.signum())
|
.filter(|(prev, curr)| prev.y.signum() != curr.y.signum())
|
||||||
.map(|(prev, _)| prev.x)
|
.map(|(prev, _)| prev.x)
|
||||||
.map(|start_x| {
|
.map(|start_x| {
|
||||||
let mut x1: f64 = start_x;
|
newtons_method(f, f_1, start_x, range.clone(), threshold).unwrap_or(f64::NAN)
|
||||||
let mut x2: f64;
|
|
||||||
let mut fail: bool = false;
|
|
||||||
loop {
|
|
||||||
x2 = x1 - (f(x1) / f_1(x1));
|
|
||||||
if !range.contains(&x2) {
|
|
||||||
fail = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If below threshold, break
|
|
||||||
if (x2 - x1).abs() < threshold {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
x1 = x2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If failed, return NaN, which is then filtered out
|
|
||||||
match fail {
|
|
||||||
true => f64::NAN,
|
|
||||||
false => x1,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.filter(|x| !x.is_nan())
|
.filter(|x| !x.is_nan())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `range` is the range of valid x values (used to stop calculation when the
|
||||||
|
/// `f` is f(x)
|
||||||
|
/// `f_1` is f'(x) aka the derivative of f(x)
|
||||||
|
/// The function returns an `Option<f64>` of the x value at which a root occurs
|
||||||
|
fn newtons_method(
|
||||||
|
f: &dyn Fn(f64) -> f64, f_1: &dyn Fn(f64) -> f64, start_x: f64, range: std::ops::Range<f64>,
|
||||||
|
threshold: f64,
|
||||||
|
) -> Option<f64> {
|
||||||
|
let mut x1: f64 = start_x;
|
||||||
|
let mut x2: f64;
|
||||||
|
let mut fail: bool = false;
|
||||||
|
loop {
|
||||||
|
x2 = x1 - (f(x1) / f_1(x1));
|
||||||
|
if !range.contains(&x2) {
|
||||||
|
fail = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If below threshold, break
|
||||||
|
if (x2 - x1).abs() < threshold {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
x1 = x2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If failed, return NaN, which is then filtered out
|
||||||
|
match fail {
|
||||||
|
true => None,
|
||||||
|
false => Some(x1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Returns a vector of length `max_i` starting at value `min_x` with resolution
|
// Returns a vector of length `max_i` starting at value `min_x` with resolution
|
||||||
// of `resolution`
|
// of `resolution`
|
||||||
pub fn resolution_helper(max_i: usize, min_x: f64, resolution: f64) -> Vec<f64> {
|
pub fn resolution_helper(max_i: usize, min_x: f64, resolution: f64) -> Vec<f64> {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user