From cd493f8d3257d18283776300cec8837d6310c987 Mon Sep 17 00:00:00 2001 From: Book-reader Date: Sat, 6 Sep 2025 15:08:40 +1200 Subject: [PATCH] Checkpoint --- asklyphe-frontend/src/math.rs | 127 ++++++++++++++++++++-------------- 1 file changed, 76 insertions(+), 51 deletions(-) diff --git a/asklyphe-frontend/src/math.rs b/asklyphe-frontend/src/math.rs index 683530c..58a6455 100644 --- a/asklyphe-frontend/src/math.rs +++ b/asklyphe-frontend/src/math.rs @@ -1,5 +1,15 @@ use tracing::{debug, error}; use once_cell::sync::Lazy; +use astro_float::{BigFloat, Sign, RoundingMode, Consts}; +use std::str::FromStr; +use std::sync::{Arc, Mutex}; +use std::mem; + +pub const PRECISION: usize = 2048; +static CONST_CACHE: Lazy>> = Lazy::new(|| Arc::new(Mutex::new(Consts::new().expect("Unable to allocate memory for Conts cache")))); +// static PI: Lazy = Lazy::new(|| BigFloat::from_str("3.141592653589793238462643383279").unwrap()); +// static E: Lazy = Lazy::new(|| BigFloat::from_str("2.718281828459045235360287471352").unwrap()); + #[derive(Debug)] pub struct Calculation { @@ -19,16 +29,16 @@ pub fn calculate(query: &str) -> Option { Some(Calculation {equation: query.to_string(), result: res.to_string()}) } -// TODO: put into own crate with dependency astro-float = "0.9.2" so I can use more than f64 -#[derive(Debug, Copy, Clone, PartialEq)] +// TODO: put into own crate with dependency astro-float = "0.9.2" so I can use more than BigFloat +#[derive(Debug, Clone, PartialEq)] enum Token { Op(Op), Atom(Atom), -/* Number(f64), +/* Number(BigFloat), Func(Func),*/ } -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq)] enum Op { Add, Subtract, @@ -64,70 +74,85 @@ impl Op { } } - fn apply_to(&self, args: &Vec) -> f64 { + fn apply_to(&self, args: &Vec) -> BigFloat { match args.len() { 1 => match self { - Op::Subtract => Some(0.0 - args[0].eval()), - Op::Add => Some(args[0].eval().abs()), - Op::Func(f) => match f { - Func::Sine => Some(args[0].eval().sin()), - Func::Cosine => Some(args[0].eval().cos()), - Func::Tangent => Some(args[0].eval().tan()), - Func::ArcSine => Some(args[0].eval().asin()), - Func::ArcCosine => Some(args[0].eval().acos()), - Func::ArcTangent => Some(args[0].eval().atan()), - Func::Log2 => Some(args[0].eval().log2()), - Func::Log10 => Some(args[0].eval().log10()), - Func::LogN => Some(args[0].eval().ln()), - Func::Square => Some(args[0].eval().powf(2.0)), - Func::SquareRoot => Some(args[0].eval().sqrt()), - Func::Abs => Some(args[0].eval().abs()), - Func::Log => None, - // _ => todo!("{:?}", self) + Op::Subtract => { + let mut res = args[0].eval(); + res.set_sign(Sign::Neg); + res + }, + Op::Add => { + let mut res = args[0].eval(); + res.set_sign(Sign::Pos); + res } - _ => None, + Op::Func(f) => match f { + Func::Sine => args[0].eval().sin(PRECISION, RoundingMode::None, &mut CONST_CACHE.lock().unwrap()), + Func::Cosine => args[0].eval().cos(PRECISION, RoundingMode::None, &mut CONST_CACHE.lock().unwrap()), + Func::Tangent => args[0].eval().tan(PRECISION, RoundingMode::None, &mut CONST_CACHE.lock().unwrap()), + Func::ArcSine => args[0].eval().asin(PRECISION, RoundingMode::None, &mut CONST_CACHE.lock().unwrap()), + Func::ArcCosine => args[0].eval().acos(PRECISION, RoundingMode::None, &mut CONST_CACHE.lock().unwrap()), + Func::ArcTangent => args[0].eval().atan(PRECISION, RoundingMode::None, &mut CONST_CACHE.lock().unwrap()), + Func::Log2 => args[0].eval().log2(PRECISION, RoundingMode::None, &mut CONST_CACHE.lock().unwrap()), + Func::Log10 => args[0].eval().log10(PRECISION, RoundingMode::None, &mut CONST_CACHE.lock().unwrap()), + Func::LogN => args[0].eval().ln(PRECISION, RoundingMode::None, &mut CONST_CACHE.lock().unwrap()), + Func::Square => args[0].eval().pow(&BigFloat::from_f64(2.0, PRECISION), PRECISION, RoundingMode::None, &mut CONST_CACHE.lock().unwrap()), + Func::SquareRoot => args[0].eval().sqrt(PRECISION, RoundingMode::None), + Func::Abs => args[0].eval().abs(), + _ => { + error!("Got 1 params for func {:?} which expects 2 (should not be possible)", self); + astro_float::NAN + }, + }, + _ => { + error!("Got 1 params for {:?} which expects 2 (should not be possible)", self); + astro_float::NAN + }, } 2 => match self { - Op::LParen => Some(args[0].eval()), - Op::RParen => Some(args[0].eval()), - Op::Add => Some(args[0].eval() + args[1].eval()), - Op::Subtract => Some(args[0].eval() - args[1].eval()), - Op::Multiply => Some(args[0].eval() * args[1].eval()), - Op::Divide => Some(args[0].eval() / args[1].eval()), - Op::Exponent => Some(args[0].eval().powf(args[1].eval())), - Op::Func(Func::Log) => Some(args[0].eval().log(args[1].eval())), - _ => None, + Op::LParen => args[0].eval(), + Op::RParen => args[0].eval(), + Op::Add => args[0].eval().add(&args[1].eval(), PRECISION, RoundingMode::None), + Op::Subtract => args[0].eval().sub(&args[1].eval(), PRECISION, RoundingMode::None), + Op::Multiply => args[0].eval().mul(&args[1].eval(), PRECISION, RoundingMode::None), + Op::Divide => args[0].eval().div(&args[1].eval(), PRECISION, RoundingMode::None), + Op::Exponent => args[0].eval().pow(&args[1].eval(), PRECISION, RoundingMode::None, &mut CONST_CACHE.lock().unwrap()), + Op::Func(Func::Log) => args[0].eval().log(&args[1].eval(), PRECISION, RoundingMode::None, &mut CONST_CACHE.lock().unwrap()), + _ => { + error!("Got 2 params for {:?} which only expects 1 (should not be possible)", self); + astro_float::NAN + }, } - _ => None, - }.unwrap_or_else(|| { - error!("ERROR when evaluating maths expression, got invalid number of args ({}) for {:?}", args.len(), self); - // None - f64::NAN - }) + _ => { + error!("Unexpected number of params ({}) for {:?} (should not be possible)", args.len(), self); + astro_float::NAN + }, + } } } -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq)] enum Atom { - Number(f64), // TODO: use the high precision floats library instead + Number(BigFloat), // TODO: use the high precision floats library instead Const(Const), } impl Atom { - fn get_val(&self) -> f64 { + fn get_val(&self) -> BigFloat { match self { Atom::Number(val) => *val, Atom::Const(c) => match c { - Const::Pi => 3.141592653589793238462643383279, - Const::E => 2.718281828459045235360287471352, - Const::Inf => f64::INFINITY, - Const::Nan => f64::NAN, + Const::Pi => CONST_CACHE.lock().unwrap().pi(PRECISION, RoundingMode::None), + Const::E => CONST_CACHE.lock().unwrap().e(PRECISION, RoundingMode::None), + Const::Inf => astro_float::INF_POS, + Const::Nan => astro_float::NAN, } } } } -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq)] enum Func { Sine, Cosine, @@ -165,7 +190,7 @@ impl Func { } } -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq)] enum Const { Pi, E, @@ -186,7 +211,7 @@ impl Const { } -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq)] enum ParseErr { Eof, Invalid, @@ -270,8 +295,8 @@ impl Lexer<'_> { } fn next(&mut self) -> Result { - let val = self.next_tok; - self.next_tok = self._next(); + let val = mem::replace(&mut self.next_tok, self._next()); + // self.next_tok = self._next(); val } @@ -383,7 +408,7 @@ enum Expr { } impl Expr { - fn eval(&self) -> f64 { + fn eval(&self) -> BigFloat { let res = match (self) { Expr::Atom(at) => at.get_val(), Expr::Node(op, exprs) => op.apply_to(exprs),