forked from asklyphe-public/asklyphe
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