This commit is contained in:
Simon Gardling 2022-03-07 13:41:25 -05:00
parent 8524d5f57e
commit 12023a3c55
3 changed files with 17 additions and 50 deletions

View File

@ -27,7 +27,7 @@ include-flate = { git = "https://github.com/Titaniumtown/include-flate.git" }
shadow-rs = { version = "0.9", default-features = false } shadow-rs = { version = "0.9", default-features = false }
const_format = { version = "0.2.22", default-features = false, features = ["fmt"] } const_format = { version = "0.2.22", default-features = false, features = ["fmt"] }
cfg-if = "1.0.0" cfg-if = "1.0.0"
meval = { git = "https://github.com/Titaniumtown/meval-rs.git" } exmex = { git = "https://github.com/bertiqwerty/exmex.git", branch = "main", features = ["partial"] }
[build-dependencies] [build-dependencies]
shadow-rs = "0.9" shadow-rs = "0.9"

View File

@ -271,7 +271,7 @@ impl MathApp {
| self.last_error.iter().any(|ele| ele.0 == i) | self.last_error.iter().any(|ele| ele.0 == i)
{ {
// let proc_func_str = self.func_strs[i].clone(); // let proc_func_str = self.func_strs[i].clone();
let func_test_output = test_func(proc_func_str.clone()); let func_test_output = test_func(&proc_func_str);
if let Some(test_output_value) = func_test_output { if let Some(test_output_value) = func_test_output {
self.last_error.push((i, test_output_value)); self.last_error.push((i, test_output_value));
} else { } else {

View File

@ -1,39 +1,28 @@
use meval::Expr; use exmex::prelude::*;
pub const EPSILON: f64 = 5.0e-7;
pub const DOUBLE_EPSILON: f64 = 10.0e-7;
type BoxFunction = Box<dyn Fn(f64) -> f64>;
pub struct BackingFunction { pub struct BackingFunction {
function: BoxFunction, function: FlatEx<f64>,
derivative: FlatEx<f64>,
} }
impl BackingFunction { impl BackingFunction {
pub fn new(func_str: &str) -> Self { pub fn new(func_str: &str) -> Self {
let function = exmex::parse::<f64>(func_str).unwrap();
Self { Self {
function: Box::new({ function: function.clone(),
let expr: Expr = func_str.parse().unwrap(); derivative: function.partial(0).unwrap(),
expr.bind("x").unwrap()
}),
} }
} }
pub fn get(&self, x: f64) -> f64 { (self.function)(x) } pub fn get(&self, x: f64) -> f64 { self.function.eval(&[x]).unwrap_or(f64::NAN) }
pub fn derivative(&self, x: f64, n: u64) -> f64 { pub fn derivative(&self, x: f64, n: u64) -> f64 {
if n == 0 { if n == 0 {
return self.get(x); self.get(x)
} } else if n == 1 {
self.derivative.eval(&[x]).unwrap_or(f64::NAN)
let (y1, y2) = ( } else {
self.derivative(x - EPSILON, n - 1), panic!("n > 1");
(self.derivative(x + EPSILON, n - 1)),
);
match y1 == y2 {
true => 0.0,
false => (y2 - y1) / DOUBLE_EPSILON,
} }
} }
} }
@ -110,33 +99,11 @@ pub fn add_asterisks(function_in: String) -> String {
} }
// Tests function to make sure it's able to be parsed. Returns the string of the Error produced, or an empty string if it runs successfully. // Tests function to make sure it's able to be parsed. Returns the string of the Error produced, or an empty string if it runs successfully.
pub fn test_func(function_string: String) -> Option<String> { pub fn test_func(function_string: &str) -> Option<String> {
// Factorials do not work, and it would be really difficult to make them work match exmex::parse::<f64>(function_string) {
if function_string.contains('!') { Err(e) => Some(e.to_string()),
return Some("Factorials are unsupported".to_string());
}
let new_func_str: String = add_asterisks(function_string);
let expr_result = new_func_str.parse();
let expr_error = match &expr_result {
Ok(_) => None, Ok(_) => None,
Err(error) => Some(format!("{}", error)),
};
if expr_error.is_some() {
return expr_error;
} }
let expr: Expr = expr_result.unwrap();
let func_result = expr.bind("x");
let func_error = match &func_result {
Ok(_) => None,
Err(error) => Some(format!("{}", error)),
};
if func_error.is_some() {
return func_error;
}
None
} }
// Tests to make sure my cursed function works as intended // Tests to make sure my cursed function works as intended