lots
This commit is contained in:
parent
e1de404665
commit
bd86998755
@ -22,12 +22,12 @@ opt-level = 2
|
|||||||
lto = false
|
lto = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
meval = { git = "https://github.com/Titaniumtown/meval-rs.git" }
|
|
||||||
eframe = { git = "https://github.com/Titaniumtown/egui", default-features = false, features = ["egui_glow"] }
|
eframe = { git = "https://github.com/Titaniumtown/egui", default-features = false, features = ["egui_glow"] }
|
||||||
include-flate = { git = "https://github.com/Titaniumtown/include-flate.git" }
|
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"
|
||||||
|
evalexpr = { git = "https://github.com/Titaniumtown/evalexpr.git" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
shadow-rs = "0.9"
|
shadow-rs = "0.9"
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
use crate::function::{FunctionEntry, RiemannSum};
|
use crate::function::{FunctionEntry, RiemannSum};
|
||||||
use crate::misc::{add_asterisks, digits_precision, test_func};
|
use crate::misc::{add_asterisks, digits_precision};
|
||||||
|
use crate::parsing::test_func;
|
||||||
|
|
||||||
use const_format::formatc;
|
use const_format::formatc;
|
||||||
use eframe::{egui, epi};
|
use eframe::{egui, epi};
|
||||||
use egui::plot::Plot;
|
use egui::plot::Plot;
|
||||||
@ -141,7 +143,7 @@ pub struct MathApp {
|
|||||||
func_strs: Vec<String>,
|
func_strs: Vec<String>,
|
||||||
|
|
||||||
// Stores last error from parsing functions (used to display the same error when side panel is minimized)
|
// Stores last error from parsing functions (used to display the same error when side panel is minimized)
|
||||||
last_error: String,
|
last_error: Vec<(usize, String)>,
|
||||||
|
|
||||||
// Stores font data that's used when displaying text
|
// Stores font data that's used when displaying text
|
||||||
font: FontData,
|
font: FontData,
|
||||||
@ -158,7 +160,7 @@ impl Default for MathApp {
|
|||||||
Self {
|
Self {
|
||||||
functions: vec![FunctionEntry::empty().integral(true)],
|
functions: vec![FunctionEntry::empty().integral(true)],
|
||||||
func_strs: vec![String::from(DEFAULT_FUNCION)],
|
func_strs: vec![String::from(DEFAULT_FUNCION)],
|
||||||
last_error: String::new(),
|
last_error: Vec::new(),
|
||||||
font: FontData::from_static(&FONT_FILE),
|
font: FontData::from_static(&FONT_FILE),
|
||||||
last_info: (vec![0.0], Duration::ZERO),
|
last_info: (vec![0.0], Duration::ZERO),
|
||||||
settings: AppSettings::default(),
|
settings: AppSettings::default(),
|
||||||
@ -230,7 +232,6 @@ impl MathApp {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let mut remove_i: Option<usize> = None;
|
let mut remove_i: Option<usize> = None;
|
||||||
self.last_error = String::new();
|
|
||||||
for (i, function) in self.functions.iter_mut().enumerate() {
|
for (i, function) in self.functions.iter_mut().enumerate() {
|
||||||
let mut integral_toggle: bool = false;
|
let mut integral_toggle: bool = false;
|
||||||
let mut derivative_toggle: bool = false;
|
let mut derivative_toggle: bool = false;
|
||||||
@ -286,8 +287,8 @@ impl MathApp {
|
|||||||
if ui
|
if ui
|
||||||
.add(Button::new("d/dx"))
|
.add(Button::new("d/dx"))
|
||||||
.on_hover_text(match derivative_enabled {
|
.on_hover_text(match derivative_enabled {
|
||||||
true => "Don't Calculate Derivative",
|
true => "Don't Differentiate",
|
||||||
false => "Calculate Derivative",
|
false => "Differentiate",
|
||||||
})
|
})
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
@ -297,12 +298,14 @@ impl MathApp {
|
|||||||
ui.text_edit_singleline(&mut self.func_strs[i]);
|
ui.text_edit_singleline(&mut self.func_strs[i]);
|
||||||
});
|
});
|
||||||
|
|
||||||
if !self.func_strs[i].is_empty() {
|
if (self.func_strs[i].clone() != function.get_func_str())
|
||||||
|
| self.last_error.iter().any(|ele| ele.0 == i)
|
||||||
|
{
|
||||||
let proc_func_str = add_asterisks(self.func_strs[i].clone());
|
let proc_func_str = add_asterisks(self.func_strs[i].clone());
|
||||||
let func_test_output = test_func(proc_func_str.clone());
|
// let proc_func_str = self.func_strs[i].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 +=
|
self.last_error.push((i, test_output_value));
|
||||||
&format!("(Function #{}) {}\n", i, test_output_value);
|
|
||||||
} else {
|
} else {
|
||||||
function.update(
|
function.update(
|
||||||
proc_func_str,
|
proc_func_str,
|
||||||
@ -321,6 +324,12 @@ impl MathApp {
|
|||||||
Some(self.settings.integral_num),
|
Some(self.settings.integral_num),
|
||||||
Some(self.settings.sum),
|
Some(self.settings.sum),
|
||||||
);
|
);
|
||||||
|
self.last_error = self
|
||||||
|
.last_error
|
||||||
|
.iter()
|
||||||
|
.filter(|(i_ele, _)| i_ele != &i)
|
||||||
|
.map(|(a, b)| (*a, b.clone()))
|
||||||
|
.collect();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
function.empty_func_str();
|
function.empty_func_str();
|
||||||
@ -470,7 +479,9 @@ impl epi::App for MathApp {
|
|||||||
CentralPanel::default().show(ctx, |ui| {
|
CentralPanel::default().show(ctx, |ui| {
|
||||||
if !self.last_error.is_empty() {
|
if !self.last_error.is_empty() {
|
||||||
ui.centered_and_justified(|ui| {
|
ui.centered_and_justified(|ui| {
|
||||||
ui.heading(self.last_error.clone());
|
self.last_error.iter().for_each(|ele| {
|
||||||
|
ui.heading(&(&format!("(Function #{}) {}\n", ele.0, ele.1)).to_string());
|
||||||
|
})
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,14 @@
|
|||||||
#![allow(clippy::too_many_arguments)] // Clippy, shut
|
#![allow(clippy::too_many_arguments)] // Clippy, shut
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::misc::{debug_log, BackingFunction, BoxFunction, SteppedVector, EPSILON};
|
use crate::misc::{debug_log, SteppedVector};
|
||||||
|
|
||||||
|
use crate::parsing::BackingFunction;
|
||||||
|
|
||||||
use eframe::egui::{
|
use eframe::egui::{
|
||||||
plot::{BarChart, Line, Value, Values},
|
plot::{BarChart, Line, Value, Values},
|
||||||
widgets::plot::Bar,
|
widgets::plot::Bar,
|
||||||
};
|
};
|
||||||
use meval::Expr;
|
|
||||||
use std::fmt::{self, Debug};
|
use std::fmt::{self, Debug};
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||||
@ -41,14 +42,11 @@ pub struct FunctionEntry {
|
|||||||
sum: RiemannSum,
|
sum: RiemannSum,
|
||||||
}
|
}
|
||||||
|
|
||||||
// x^2 function, set here so we don't have to regenerate it every time a new function is made
|
|
||||||
fn default_function(x: f64) -> f64 { x.powi(2) }
|
|
||||||
|
|
||||||
impl FunctionEntry {
|
impl FunctionEntry {
|
||||||
// Creates Empty Function instance
|
// Creates Empty Function instance
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
Self {
|
Self {
|
||||||
function: BackingFunction::new(Box::new(default_function)),
|
function: BackingFunction::new("x^2").unwrap(),
|
||||||
func_str: String::new(),
|
func_str: String::new(),
|
||||||
min_x: -1.0,
|
min_x: -1.0,
|
||||||
max_x: 1.0,
|
max_x: 1.0,
|
||||||
@ -76,10 +74,7 @@ impl FunctionEntry {
|
|||||||
// If the function string changes, just wipe and restart from scratch
|
// If the function string changes, just wipe and restart from scratch
|
||||||
if func_str != self.func_str {
|
if func_str != self.func_str {
|
||||||
self.func_str = func_str.clone();
|
self.func_str = func_str.clone();
|
||||||
self.function = BackingFunction::new(Box::new({
|
self.function = BackingFunction::new(&func_str).unwrap();
|
||||||
let expr: Expr = func_str.parse().unwrap();
|
|
||||||
expr.bind("x").unwrap()
|
|
||||||
}));
|
|
||||||
self.back_cache = None;
|
self.back_cache = None;
|
||||||
self.front_cache = None;
|
self.front_cache = None;
|
||||||
self.derivative_cache = None;
|
self.derivative_cache = None;
|
||||||
@ -245,7 +240,7 @@ impl FunctionEntry {
|
|||||||
let step = (self.integral_min_x - self.integral_max_x).abs() / (self.integral_num as f64);
|
let step = (self.integral_min_x - self.integral_max_x).abs() / (self.integral_num as f64);
|
||||||
|
|
||||||
let mut area: f64 = 0.0;
|
let mut area: f64 = 0.0;
|
||||||
let data2: Vec<(f64, f64, f64)> = (1..=self.integral_num)
|
let data2: Vec<(f64, f64, f64)> = (0..self.integral_num)
|
||||||
.map(|e| {
|
.map(|e| {
|
||||||
let x: f64 = ((e as f64) * step) + self.integral_min_x;
|
let x: f64 = ((e as f64) * step) + self.integral_min_x;
|
||||||
let step_offset = step * x.signum(); // store the offset here so it doesn't have to be calculated multiple times
|
let step_offset = step * x.signum(); // store the offset here so it doesn't have to be calculated multiple times
|
||||||
@ -293,16 +288,19 @@ impl FunctionEntry {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn integral_num(mut self, integral_num: usize) -> Self {
|
pub fn integral_num(mut self, integral_num: usize) -> Self {
|
||||||
self.integral_num = integral_num;
|
self.integral_num = integral_num;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn pixel_width(mut self, pixel_width: usize) -> Self {
|
pub fn pixel_width(mut self, pixel_width: usize) -> Self {
|
||||||
self.pixel_width = pixel_width;
|
self.pixel_width = pixel_width;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn integral_bounds(mut self, min_x: f64, max_x: f64) -> Self {
|
pub fn integral_bounds(mut self, min_x: f64, max_x: f64) -> Self {
|
||||||
if min_x >= max_x {
|
if min_x >= max_x {
|
||||||
panic!("integral_bounds: min_x is larger than max_x");
|
panic!("integral_bounds: min_x is larger than max_x");
|
||||||
@ -353,9 +351,10 @@ fn left_function_test() {
|
|||||||
(0.8, 1.5999999999349868),
|
(0.8, 1.5999999999349868),
|
||||||
];
|
];
|
||||||
|
|
||||||
let area_target = 0.8720000000000001;
|
let area_target = 0.9600000000000001;
|
||||||
|
|
||||||
let vec_bars_target = vec![
|
let vec_bars_target = vec![
|
||||||
|
1.44,
|
||||||
1.0,
|
1.0,
|
||||||
0.6400000000000001,
|
0.6400000000000001,
|
||||||
0.3599999999999998,
|
0.3599999999999998,
|
||||||
@ -365,20 +364,19 @@ fn left_function_test() {
|
|||||||
0.16000000000000011,
|
0.16000000000000011,
|
||||||
0.3600000000000001,
|
0.3600000000000001,
|
||||||
0.6400000000000001,
|
0.6400000000000001,
|
||||||
1.0,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
let vec_integral_target = vec![
|
let vec_integral_target = vec![
|
||||||
(-0.9, 0.2),
|
(-1.1, 0.288),
|
||||||
(-0.7, 0.32800000000000007),
|
(-0.9, 0.488),
|
||||||
(-0.4999999999999999, 0.4),
|
(-0.7, 0.616),
|
||||||
(-0.29999999999999993, 0.432),
|
(-0.4999999999999999, 0.688),
|
||||||
(0.1, 0.432),
|
(-0.29999999999999993, 0.72),
|
||||||
(0.30000000000000016, 0.44),
|
(0.1, 0.72),
|
||||||
(0.5000000000000001, 0.47200000000000003),
|
(0.30000000000000016, 0.728),
|
||||||
(0.7000000000000001, 0.544),
|
(0.5000000000000001, 0.76),
|
||||||
(0.9, 0.672),
|
(0.7000000000000001, 0.8320000000000001),
|
||||||
(1.1, 0.8720000000000001),
|
(0.9, 0.9600000000000001),
|
||||||
];
|
];
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -476,9 +474,10 @@ fn middle_function_test() {
|
|||||||
(0.8, 1.5999999999349868),
|
(0.8, 1.5999999999349868),
|
||||||
];
|
];
|
||||||
|
|
||||||
let area_target = 0.9200000000000002;
|
let area_target = 0.92;
|
||||||
|
|
||||||
let vec_bars_target = vec![
|
let vec_bars_target = vec![
|
||||||
|
1.22,
|
||||||
0.8200000000000001,
|
0.8200000000000001,
|
||||||
0.5,
|
0.5,
|
||||||
0.2599999999999999,
|
0.2599999999999999,
|
||||||
@ -488,20 +487,19 @@ fn middle_function_test() {
|
|||||||
0.2600000000000001,
|
0.2600000000000001,
|
||||||
0.5000000000000001,
|
0.5000000000000001,
|
||||||
0.8200000000000001,
|
0.8200000000000001,
|
||||||
1.22,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
let vec_integral_target = vec![
|
let vec_integral_target = vec![
|
||||||
(-0.9, 0.16400000000000003),
|
(-1.1, 0.244),
|
||||||
(-0.7, 0.264),
|
(-0.9, 0.40800000000000003),
|
||||||
(-0.4999999999999999, 0.316),
|
(-0.7, 0.508),
|
||||||
(-0.29999999999999993, 0.336),
|
(-0.4999999999999999, 0.5599999999999999),
|
||||||
(0.1, 0.34),
|
(-0.29999999999999993, 0.58),
|
||||||
(0.30000000000000016, 0.36000000000000004),
|
(0.1, 0.584),
|
||||||
(0.5000000000000001, 0.4120000000000001),
|
(0.30000000000000016, 0.604),
|
||||||
(0.7000000000000001, 0.5120000000000001),
|
(0.5000000000000001, 0.656),
|
||||||
(0.9, 0.6760000000000002),
|
(0.7000000000000001, 0.756),
|
||||||
(1.1, 0.9200000000000002),
|
(0.9, 0.92),
|
||||||
];
|
];
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -599,9 +597,10 @@ fn right_function_test() {
|
|||||||
(0.8, 1.5999999999349868),
|
(0.8, 1.5999999999349868),
|
||||||
];
|
];
|
||||||
|
|
||||||
let area_target = 0.9680000000000002;
|
let area_target = 0.8800000000000001;
|
||||||
|
|
||||||
let vec_bars_target = vec![
|
let vec_bars_target = vec![
|
||||||
|
1.0,
|
||||||
0.6400000000000001,
|
0.6400000000000001,
|
||||||
0.36,
|
0.36,
|
||||||
0.15999999999999992,
|
0.15999999999999992,
|
||||||
@ -611,20 +610,19 @@ fn right_function_test() {
|
|||||||
0.3600000000000001,
|
0.3600000000000001,
|
||||||
0.6400000000000001,
|
0.6400000000000001,
|
||||||
1.0,
|
1.0,
|
||||||
1.44,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
let vec_integral_target = vec![
|
let vec_integral_target = vec![
|
||||||
(-0.9, 0.12800000000000003),
|
(-1.1, 0.2),
|
||||||
(-0.7, 0.2),
|
(-0.9, 0.32800000000000007),
|
||||||
(-0.4999999999999999, 0.23199999999999998),
|
(-0.7, 0.4000000000000001),
|
||||||
(-0.29999999999999993, 0.24),
|
(-0.4999999999999999, 0.43200000000000005),
|
||||||
(0.1, 0.248),
|
(-0.29999999999999993, 0.44000000000000006),
|
||||||
(0.30000000000000016, 0.28),
|
(0.1, 0.44800000000000006),
|
||||||
(0.5000000000000001, 0.35200000000000004),
|
(0.30000000000000016, 0.4800000000000001),
|
||||||
(0.7000000000000001, 0.4800000000000001),
|
(0.5000000000000001, 0.5520000000000002),
|
||||||
(0.9, 0.6800000000000002),
|
(0.7000000000000001, 0.6800000000000002),
|
||||||
(1.1, 0.9680000000000002),
|
(0.9, 0.8800000000000001),
|
||||||
];
|
];
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
mod egui_app;
|
mod egui_app;
|
||||||
mod function;
|
mod function;
|
||||||
mod misc;
|
mod misc;
|
||||||
|
mod parsing;
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(target_arch = "wasm32")] {
|
if #[cfg(target_arch = "wasm32")] {
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
mod egui_app;
|
mod egui_app;
|
||||||
mod function;
|
mod function;
|
||||||
mod misc;
|
mod misc;
|
||||||
|
mod parsing;
|
||||||
|
|
||||||
// For running the program natively! (Because why not?)
|
// For running the program natively! (Because why not?)
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
|||||||
89
src/misc.rs
89
src/misc.rs
@ -1,67 +1,32 @@
|
|||||||
use meval::Expr;
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(target_arch = "wasm32")] {
|
||||||
#[cfg(target_arch = "wasm32")]
|
use wasm_bindgen::prelude::*;
|
||||||
use wasm_bindgen::prelude::*;
|
#[wasm_bindgen]
|
||||||
#[cfg(target_arch = "wasm32")]
|
extern "C" {
|
||||||
#[wasm_bindgen]
|
// Use `js_namespace` here to bind `console.log(..)` instead of just
|
||||||
extern "C" {
|
// `log(..)`
|
||||||
// Use `js_namespace` here to bind `console.log(..)` instead of just
|
#[wasm_bindgen(js_namespace = console)]
|
||||||
// `log(..)`
|
fn log(s: &str);
|
||||||
#[wasm_bindgen(js_namespace = console)]
|
|
||||||
fn log(s: &str);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn log_helper(s: &str) {
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
log(s);
|
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
println!("{}", s);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn debug_log(s: &str) {
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
log(s);
|
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
println!("{}", s);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(debug_assertions))]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn debug_log(_s: &str) {}
|
|
||||||
|
|
||||||
pub const EPSILON: f64 = 5.0e-7;
|
|
||||||
|
|
||||||
pub type BoxFunction = Box<dyn Fn(f64) -> f64>;
|
|
||||||
|
|
||||||
pub struct BackingFunction {
|
|
||||||
function: BoxFunction,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BackingFunction {
|
|
||||||
pub fn new(function: BoxFunction) -> BackingFunction { BackingFunction { function } }
|
|
||||||
|
|
||||||
pub fn get(&self, x: f64) -> f64 { (self.function)(x) }
|
|
||||||
|
|
||||||
pub fn derivative(&self, x: f64, n: u64) -> f64 {
|
|
||||||
if n == 0 {
|
|
||||||
return self.get(x);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (x1, x2) = (x - EPSILON, x + EPSILON);
|
#[allow(dead_code)]
|
||||||
let (y1, y2) = (self.derivative(x1, n - 1), (self.derivative(x2, n - 1)));
|
pub fn log_helper(s: &str) {
|
||||||
(y2 - y1) / (EPSILON * 2.0)
|
log(s);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl From<BoxFunction> for BackingFunction {
|
#[allow(dead_code)]
|
||||||
fn from(boxfunction: BoxFunction) -> BackingFunction {
|
pub fn debug_log(s: &str) {
|
||||||
BackingFunction {
|
log(s);
|
||||||
function: boxfunction,
|
}
|
||||||
|
} else {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn log_helper(s: &str) {
|
||||||
|
println!("{}", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn debug_log(s: &str) {
|
||||||
|
println!("{}", s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,6 +102,7 @@ pub fn add_asterisks(function_in: String) -> String {
|
|||||||
output_string.replace('π', "pi") // π -> pi
|
output_string.replace('π', "pi") // π -> pi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// 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: String) -> Option<String> {
|
||||||
// Factorials do not work, and it would be really difficult to make them work
|
// Factorials do not work, and it would be really difficult to make them work
|
||||||
@ -166,6 +132,7 @@ pub fn test_func(function_string: String) -> Option<String> {
|
|||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
pub struct SteppedVector {
|
pub struct SteppedVector {
|
||||||
data: Vec<f64>,
|
data: Vec<f64>,
|
||||||
|
|||||||
61
src/parsing.rs
Normal file
61
src/parsing.rs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
use evalexpr::*;
|
||||||
|
|
||||||
|
pub const EPSILON: f64 = 5.0e-7;
|
||||||
|
pub const DOUBLE_EPSILON: f64 = 10.0e-7;
|
||||||
|
|
||||||
|
pub fn test_func(func_str: &str) -> Option<String> {
|
||||||
|
let precompiled = build_operator_tree(&("x = 10;".to_owned() + func_str));
|
||||||
|
|
||||||
|
match precompiled {
|
||||||
|
Ok(_) => {
|
||||||
|
let precompiled2 = precompiled.unwrap().eval();
|
||||||
|
match precompiled2 {
|
||||||
|
Ok(_) => None,
|
||||||
|
Err(e) => Some(e.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => Some(e.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BackingFunction {
|
||||||
|
node: Node,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BackingFunction {
|
||||||
|
pub fn new(func_str: &str) -> Result<Self, String> {
|
||||||
|
let precompiled = build_operator_tree(func_str);
|
||||||
|
|
||||||
|
match precompiled {
|
||||||
|
Ok(_) => Ok(Self {
|
||||||
|
node: precompiled.unwrap(),
|
||||||
|
}),
|
||||||
|
Err(e) => Err(e.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, _x: f64) -> f64 {
|
||||||
|
let context: HashMapContext = context_map! {
|
||||||
|
"x" => 0,
|
||||||
|
"e" => std::f64::consts::E,
|
||||||
|
"pi" => std::f64::consts::PI,
|
||||||
|
}
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
self.node
|
||||||
|
.eval_with_context(&context)
|
||||||
|
.unwrap()
|
||||||
|
.as_number()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn derivative(&self, x: f64, n: u64) -> f64 {
|
||||||
|
if n == 0 {
|
||||||
|
return self.get(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (x1, x2) = (x - EPSILON, x + EPSILON);
|
||||||
|
let (y1, y2) = (self.derivative(x1, n - 1), (self.derivative(x2, n - 1)));
|
||||||
|
(y2 - y1) / DOUBLE_EPSILON
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user