diff --git a/src/nodes/eval.rs b/src/nodes/eval.rs index 2ebfee0..33c606b 100644 --- a/src/nodes/eval.rs +++ b/src/nodes/eval.rs @@ -83,111 +83,41 @@ fn collapse_toplevel(nodes: &mut Vec, mut end: usize) -> Result<(), Error> return Err(Error::MissingArgument(node.clone())); }; - function.for_float()(n); + function.apply_to(n); nodes.remove(start + index); end -= 1; } - while let Some(operator) = nodes[start..end] - .iter() - .position(|n| *n == Node::Operator(Operator::Exp)) - { - let lhs = match nodes.remove(start + operator - 1) { - Node::Number(n) => n, - n => return Err(Error::InvalidOperand(n)), - }; - end -= 1; - match nodes.get_mut(start + operator) { - None => return Err(Error::OutOfBounds(Nodes(nodes.clone()), start + operator)), + macro_rules! collapse_operator { + ($operator:expr) => { + while let Some(index) = nodes[start..end] + .iter() + .position(|n| *n == Node::Operator($operator)) + { + let lhs = match nodes.remove(start + index - 1) { + Node::Number(n) => n, + n => return Err(Error::InvalidOperand(n)), + }; + end -= 1; + match nodes.get_mut(start + index) { + None => return Err(Error::OutOfBounds(Nodes(nodes.clone()), start + index)), - Some(Node::Number(n)) => n.pow_from(lhs), - Some(n) => return Err(Error::InvalidOperand(n.clone())), - }; + Some(Node::Number(n)) => $operator.apply_to(n, lhs), + Some(n) => return Err(Error::InvalidOperand(n.clone())), + }; - nodes.remove(start + operator - 1); - end -= 1; + nodes.remove(start + index - 1); + end -= 1; + } + }; } - while let Some(operator) = nodes[start..end] - .iter() - .position(|n| *n == Node::Operator(Operator::Div)) - { - let lhs = match nodes.remove(start + operator - 1) { - Node::Number(n) => n, - n => return Err(Error::InvalidOperand(n)), - }; - end -= 1; - match nodes.get_mut(start + operator) { - None => return Err(Error::OutOfBounds(Nodes(nodes.clone()), start + operator)), - - Some(Node::Number(n)) => n.div_from(lhs), - Some(n) => return Err(Error::InvalidOperand(n.clone())), - }; - - nodes.remove(start + operator - 1); - end -= 1; - } - - while let Some(operator) = nodes[start..end] - .iter() - .position(|n| *n == Node::Operator(Operator::Mult)) - { - let lhs = match nodes.remove(start + operator - 1) { - Node::Number(n) => n, - n => return Err(Error::InvalidOperand(n)), - }; - end -= 1; - match nodes.get_mut(start + operator) { - None => return Err(Error::OutOfBounds(Nodes(nodes.clone()), start + operator)), - - Some(Node::Number(n)) => n.mul_from(lhs), - Some(n) => return Err(Error::InvalidOperand(n.clone())), - }; - - nodes.remove(start + operator - 1); - end -= 1; - } - - while let Some(operator) = nodes[start..end] - .iter() - .position(|n| *n == Node::Operator(Operator::Minus)) - { - let lhs = match nodes.remove(start + operator - 1) { - Node::Number(n) => n, - n => return Err(Error::InvalidOperand(n)), - }; - end -= 1; - match nodes.get_mut(start + operator) { - None => return Err(Error::OutOfBounds(Nodes(nodes.clone()), start + operator)), - - Some(Node::Number(n)) => n.sub_from(lhs), - Some(n) => return Err(Error::InvalidOperand(n.clone())), - }; - - nodes.remove(start + operator - 1); - end -= 1; - } - - while let Some(operator) = nodes[start..end] - .iter() - .position(|n| *n == Node::Operator(Operator::Plus)) - { - let lhs = match nodes.remove(start + operator - 1) { - Node::Number(n) => n, - n => return Err(Error::InvalidOperand(n)), - }; - end -= 1; - match nodes.get_mut(start + operator) { - None => return Err(Error::OutOfBounds(Nodes(nodes.clone()), start + operator)), - - Some(Node::Number(n)) => n.add_from(lhs), - Some(n) => return Err(Error::InvalidOperand(n.clone())), - }; - - nodes.remove(start + operator - 1); - end -= 1; - } + collapse_operator!(Operator::Exp); + collapse_operator!(Operator::Div); + collapse_operator!(Operator::Mult); + collapse_operator!(Operator::Minus); + collapse_operator!(Operator::Plus); if nodes.len() > 1 { nodes.remove(end); @@ -197,21 +127,32 @@ fn collapse_toplevel(nodes: &mut Vec, mut end: usize) -> Result<(), Error> Ok(()) } -impl Function { - fn for_float(&self) -> impl FnMut(&mut Float) { +impl Operator { + fn apply_to(&self, rhs: &mut Float, lhs: Float) { match self { - Function::Sqrt => Float::sqrt_mut, + Self::Plus => Float::add_from(rhs, lhs), + Self::Minus => Float::sub_from(rhs, lhs), + Self::Mult => Float::mul_from(rhs, lhs), + Self::Div => Float::div_from(rhs, lhs), + Self::Exp => Float::pow_from(rhs, lhs), + } + } +} +impl Function { + fn apply_to(&self, n: &mut Float) { + match self { + Self::Sqrt => Float::sqrt_mut(n), - Function::Ln => Float::ln_mut, + Self::Ln => Float::ln_mut(n), - Function::Sine => Float::sin_mut, - Function::ArcSine => Float::asin_mut, - Function::Cosine => Float::cos_mut, - Function::ArcCosine => Float::acos_mut, - Function::Tangent => Float::tan_mut, - Function::ArcTangent => Float::atan_mut, - Function::Secant => Float::sec_mut, - Function::CoSecant => Float::csc_mut, + Self::Sine => Float::sin_mut(n), + Self::ArcSine => Float::asin_mut(n), + Self::Cosine => Float::cos_mut(n), + Self::ArcCosine => Float::acos_mut(n), + Self::Tangent => Float::tan_mut(n), + Self::ArcTangent => Float::atan_mut(n), + Self::Secant => Float::sec_mut(n), + Self::CoSecant => Float::csc_mut(n), } } } diff --git a/src/nodes/parse.rs b/src/nodes/parse.rs index 96d4236..e3da6e6 100644 --- a/src/nodes/parse.rs +++ b/src/nodes/parse.rs @@ -1,7 +1,10 @@ use core::f64; use std::str::FromStr; -use rug::{Float, float::ParseFloatError}; +use rug::{ + Float, + float::{self, ParseFloatError}, +}; use crate::nodes::{Function, Node, Nodes, Operator}; @@ -10,7 +13,7 @@ impl Node { Ok(match s { "c" => Self::from(299_792_458), "A" => Self::from(6.02214076e23), - "pi" | "π" => Self::from(f64::consts::PI), + "pi" | "π" => Self::from(float::Constant::Pi), // Planck's constant, in J*s (joule-seconds) "h" => Self::from(6.62607015e-34), "e" => Self::from(f64::consts::E), diff --git a/src/nodes/tests.rs b/src/nodes/tests.rs index 15b6c21..2f22d8a 100644 --- a/src/nodes/tests.rs +++ b/src/nodes/tests.rs @@ -51,3 +51,8 @@ fn constant_implicit_mult() { assert_eq!(eval("2pi"), 6.283185307179586); assert_eq!(eval("pi2"), 6.283185307179586); } + +#[test] +fn pi_precision() { + assert_eq!(eval("sin(pi)"), 0.) +}