Checkpoint
This commit is contained in:
		
							parent
							
								
									74b29455e5
								
							
						
					
					
						commit
						cd493f8d32
					
				
					 1 changed files with 76 additions and 51 deletions
				
			
		| 
						 | 
					@ -1,5 +1,15 @@
 | 
				
			||||||
use tracing::{debug, error};
 | 
					use tracing::{debug, error};
 | 
				
			||||||
use once_cell::sync::Lazy;
 | 
					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<Arc<Mutex<Consts>>> = Lazy::new(|| Arc::new(Mutex::new(Consts::new().expect("Unable to allocate memory for Conts cache"))));
 | 
				
			||||||
 | 
					// static PI: Lazy<BigFloat> = Lazy::new(|| BigFloat::from_str("3.141592653589793238462643383279").unwrap());
 | 
				
			||||||
 | 
					// static E: Lazy<BigFloat> = Lazy::new(|| BigFloat::from_str("2.718281828459045235360287471352").unwrap());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct Calculation {
 | 
					pub struct Calculation {
 | 
				
			||||||
| 
						 | 
					@ -19,16 +29,16 @@ pub fn calculate(query: &str) -> Option<Calculation> {
 | 
				
			||||||
	Some(Calculation {equation: query.to_string(), result: res.to_string()})
 | 
						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
 | 
					// TODO: put into own crate with dependency astro-float = "0.9.2" so I can use more than BigFloat
 | 
				
			||||||
#[derive(Debug, Copy, Clone, PartialEq)]
 | 
					#[derive(Debug, Clone, PartialEq)]
 | 
				
			||||||
enum Token {
 | 
					enum Token {
 | 
				
			||||||
	Op(Op),
 | 
						Op(Op),
 | 
				
			||||||
	Atom(Atom),
 | 
						Atom(Atom),
 | 
				
			||||||
/*	Number(f64),
 | 
					/*	Number(BigFloat),
 | 
				
			||||||
	Func(Func),*/
 | 
						Func(Func),*/
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Copy, Clone, PartialEq)]
 | 
					#[derive(Debug, Clone, PartialEq)]
 | 
				
			||||||
enum Op {
 | 
					enum Op {
 | 
				
			||||||
	Add,
 | 
						Add,
 | 
				
			||||||
	Subtract,
 | 
						Subtract,
 | 
				
			||||||
| 
						 | 
					@ -64,70 +74,85 @@ impl Op {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn apply_to(&self, args: &Vec<Expr>) -> f64 {
 | 
						fn apply_to(&self, args: &Vec<Expr>) -> BigFloat {
 | 
				
			||||||
		match args.len() {
 | 
							match args.len() {
 | 
				
			||||||
			1 => match self {
 | 
								1 => match self {
 | 
				
			||||||
				Op::Subtract => Some(0.0 - args[0].eval()),
 | 
									Op::Subtract => {
 | 
				
			||||||
				Op::Add => Some(args[0].eval().abs()),
 | 
										let mut res = args[0].eval();
 | 
				
			||||||
				Op::Func(f) => match f {
 | 
										res.set_sign(Sign::Neg);
 | 
				
			||||||
					Func::Sine => Some(args[0].eval().sin()),
 | 
										res
 | 
				
			||||||
					Func::Cosine => Some(args[0].eval().cos()),
 | 
									},
 | 
				
			||||||
					Func::Tangent => Some(args[0].eval().tan()),
 | 
									Op::Add => {
 | 
				
			||||||
					Func::ArcSine => Some(args[0].eval().asin()),
 | 
										let mut res = args[0].eval();
 | 
				
			||||||
					Func::ArcCosine => Some(args[0].eval().acos()),
 | 
										res.set_sign(Sign::Pos);
 | 
				
			||||||
					Func::ArcTangent => Some(args[0].eval().atan()),
 | 
										res
 | 
				
			||||||
					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)
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				_ => 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 {
 | 
								2 => match self {
 | 
				
			||||||
				Op::LParen => Some(args[0].eval()),
 | 
									Op::LParen => args[0].eval(),
 | 
				
			||||||
				Op::RParen => Some(args[0].eval()),
 | 
									Op::RParen => args[0].eval(),
 | 
				
			||||||
				Op::Add => Some(args[0].eval() + args[1].eval()),
 | 
									Op::Add => args[0].eval().add(&args[1].eval(), PRECISION, RoundingMode::None),
 | 
				
			||||||
				Op::Subtract => Some(args[0].eval() - args[1].eval()),
 | 
									Op::Subtract => args[0].eval().sub(&args[1].eval(), PRECISION, RoundingMode::None),
 | 
				
			||||||
				Op::Multiply => Some(args[0].eval() * args[1].eval()),
 | 
									Op::Multiply => args[0].eval().mul(&args[1].eval(), PRECISION, RoundingMode::None),
 | 
				
			||||||
				Op::Divide => Some(args[0].eval() / args[1].eval()),
 | 
									Op::Divide => args[0].eval().div(&args[1].eval(), PRECISION, RoundingMode::None),
 | 
				
			||||||
				Op::Exponent => Some(args[0].eval().powf(args[1].eval())),
 | 
									Op::Exponent => args[0].eval().pow(&args[1].eval(), PRECISION, RoundingMode::None, &mut CONST_CACHE.lock().unwrap()),
 | 
				
			||||||
				Op::Func(Func::Log) => Some(args[0].eval().log(args[1].eval())),
 | 
									Op::Func(Func::Log) => args[0].eval().log(&args[1].eval(), PRECISION, RoundingMode::None, &mut CONST_CACHE.lock().unwrap()),
 | 
				
			||||||
				_ => None,
 | 
									_ => {
 | 
				
			||||||
 | 
										error!("Got 2 params for {:?} which only expects 1 (should not be possible)", self);
 | 
				
			||||||
 | 
										astro_float::NAN
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			_ => None,
 | 
								_ => {
 | 
				
			||||||
		}.unwrap_or_else(|| {
 | 
									error!("Unexpected number of params ({}) for {:?} (should not be possible)", args.len(), self);
 | 
				
			||||||
			error!("ERROR when evaluating maths expression, got invalid number of args ({}) for {:?}", args.len(), self);
 | 
									astro_float::NAN
 | 
				
			||||||
			// None
 | 
								},
 | 
				
			||||||
			f64::NAN
 | 
							}
 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Copy, Clone, PartialEq)]
 | 
					#[derive(Debug, Clone, PartialEq)]
 | 
				
			||||||
enum Atom {
 | 
					enum Atom {
 | 
				
			||||||
	Number(f64), // TODO: use the high precision floats library instead
 | 
						Number(BigFloat), // TODO: use the high precision floats library instead
 | 
				
			||||||
	Const(Const),
 | 
						Const(Const),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Atom {
 | 
					impl Atom {
 | 
				
			||||||
	fn get_val(&self) -> f64 {
 | 
						fn get_val(&self) -> BigFloat {
 | 
				
			||||||
		match self {
 | 
							match self {
 | 
				
			||||||
			Atom::Number(val) => *val,
 | 
								Atom::Number(val) => *val,
 | 
				
			||||||
			Atom::Const(c) => match c {
 | 
								Atom::Const(c) => match c {
 | 
				
			||||||
				Const::Pi => 3.141592653589793238462643383279,
 | 
									Const::Pi => CONST_CACHE.lock().unwrap().pi(PRECISION, RoundingMode::None),
 | 
				
			||||||
				Const::E => 2.718281828459045235360287471352,
 | 
									Const::E => CONST_CACHE.lock().unwrap().e(PRECISION, RoundingMode::None),
 | 
				
			||||||
				Const::Inf => f64::INFINITY,
 | 
									Const::Inf => astro_float::INF_POS,
 | 
				
			||||||
				Const::Nan => f64::NAN,
 | 
									Const::Nan => astro_float::NAN,
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Copy, Clone, PartialEq)]
 | 
					#[derive(Debug, Clone, PartialEq)]
 | 
				
			||||||
enum Func {
 | 
					enum Func {
 | 
				
			||||||
	Sine,
 | 
						Sine,
 | 
				
			||||||
	Cosine,
 | 
						Cosine,
 | 
				
			||||||
| 
						 | 
					@ -165,7 +190,7 @@ impl Func {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Copy, Clone, PartialEq)]
 | 
					#[derive(Debug, Clone, PartialEq)]
 | 
				
			||||||
enum Const {
 | 
					enum Const {
 | 
				
			||||||
	Pi,
 | 
						Pi,
 | 
				
			||||||
	E,
 | 
						E,
 | 
				
			||||||
| 
						 | 
					@ -186,7 +211,7 @@ impl Const {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Copy, Clone, PartialEq)]
 | 
					#[derive(Debug, Clone, PartialEq)]
 | 
				
			||||||
enum ParseErr {
 | 
					enum ParseErr {
 | 
				
			||||||
	Eof,
 | 
						Eof,
 | 
				
			||||||
	Invalid,
 | 
						Invalid,
 | 
				
			||||||
| 
						 | 
					@ -270,8 +295,8 @@ impl Lexer<'_> {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn next(&mut self) -> Result<Token, ParseErr> {
 | 
						fn next(&mut self) -> Result<Token, ParseErr> {
 | 
				
			||||||
		let val = self.next_tok;
 | 
							let val = mem::replace(&mut self.next_tok, self._next());
 | 
				
			||||||
		self.next_tok = self._next();
 | 
							// self.next_tok = self._next();
 | 
				
			||||||
		val
 | 
							val
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -383,7 +408,7 @@ enum Expr {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Expr {
 | 
					impl Expr {
 | 
				
			||||||
	fn eval(&self) -> f64 {
 | 
						fn eval(&self) -> BigFloat {
 | 
				
			||||||
		let res = match (self) {
 | 
							let res = match (self) {
 | 
				
			||||||
			Expr::Atom(at) => at.get_val(),
 | 
								Expr::Atom(at) => at.get_val(),
 | 
				
			||||||
			Expr::Node(op, exprs) => op.apply_to(exprs),
 | 
								Expr::Node(op, exprs) => op.apply_to(exprs),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue