Compare commits

...
Author SHA1 Message Date
f1f9c11a04
feat: use more precise pi
with pretty_eval, I still get:
-9.194801691 * 10^-618

but at least that's more accurate than the prior:
1.224646799 * 10^-16
2026-10-20 21:27:40 -07:00
0ede27e927
refactor: rename confusing index variable 2026-10-20 19:26:14 -07:00
9bd0318702
refactor: make Operator/Function ordering consistent 2026-10-20 18:00:08 -07:00
56e8fbca99
refactor: nicer operator/function eval functions 2026-10-20 17:58:57 -07:00
570da21956
refactor: replace duplicate eval code with macro 2026-10-20 17:42:50 -07:00
3 changed files with 61 additions and 112 deletions

View file

@ -83,111 +83,41 @@ fn collapse_toplevel(nodes: &mut Vec<Node>, mut end: usize) -> Result<(), Error>
return Err(Error::MissingArgument(node.clone())); return Err(Error::MissingArgument(node.clone()));
}; };
function.for_float()(n); function.apply_to(n);
nodes.remove(start + index); nodes.remove(start + index);
end -= 1; end -= 1;
} }
while let Some(operator) = nodes[start..end] macro_rules! collapse_operator {
.iter() ($operator:expr) => {
.position(|n| *n == Node::Operator(Operator::Exp)) while let Some(index) = nodes[start..end]
{ .iter()
let lhs = match nodes.remove(start + operator - 1) { .position(|n| *n == Node::Operator($operator))
Node::Number(n) => n, {
n => return Err(Error::InvalidOperand(n)), let lhs = match nodes.remove(start + index - 1) {
}; Node::Number(n) => n,
end -= 1; n => return Err(Error::InvalidOperand(n)),
match nodes.get_mut(start + operator) { };
None => return Err(Error::OutOfBounds(Nodes(nodes.clone()), start + operator)), 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(Node::Number(n)) => $operator.apply_to(n, lhs),
Some(n) => return Err(Error::InvalidOperand(n.clone())), Some(n) => return Err(Error::InvalidOperand(n.clone())),
}; };
nodes.remove(start + operator - 1); nodes.remove(start + index - 1);
end -= 1; end -= 1;
}
};
} }
while let Some(operator) = nodes[start..end] collapse_operator!(Operator::Exp);
.iter() collapse_operator!(Operator::Div);
.position(|n| *n == Node::Operator(Operator::Div)) collapse_operator!(Operator::Mult);
{ collapse_operator!(Operator::Minus);
let lhs = match nodes.remove(start + operator - 1) { collapse_operator!(Operator::Plus);
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;
}
if nodes.len() > 1 { if nodes.len() > 1 {
nodes.remove(end); nodes.remove(end);
@ -197,21 +127,32 @@ fn collapse_toplevel(nodes: &mut Vec<Node>, mut end: usize) -> Result<(), Error>
Ok(()) Ok(())
} }
impl Function { impl Operator {
fn for_float(&self) -> impl FnMut(&mut Float) { fn apply_to(&self, rhs: &mut Float, lhs: Float) {
match self { 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, Self::Sine => Float::sin_mut(n),
Function::ArcSine => Float::asin_mut, Self::ArcSine => Float::asin_mut(n),
Function::Cosine => Float::cos_mut, Self::Cosine => Float::cos_mut(n),
Function::ArcCosine => Float::acos_mut, Self::ArcCosine => Float::acos_mut(n),
Function::Tangent => Float::tan_mut, Self::Tangent => Float::tan_mut(n),
Function::ArcTangent => Float::atan_mut, Self::ArcTangent => Float::atan_mut(n),
Function::Secant => Float::sec_mut, Self::Secant => Float::sec_mut(n),
Function::CoSecant => Float::csc_mut, Self::CoSecant => Float::csc_mut(n),
} }
} }
} }

View file

@ -1,7 +1,10 @@
use core::f64; use core::f64;
use std::str::FromStr; use std::str::FromStr;
use rug::{Float, float::ParseFloatError}; use rug::{
Float,
float::{self, ParseFloatError},
};
use crate::nodes::{Function, Node, Nodes, Operator}; use crate::nodes::{Function, Node, Nodes, Operator};
@ -10,7 +13,7 @@ impl Node {
Ok(match s { Ok(match s {
"c" => Self::from(299_792_458), "c" => Self::from(299_792_458),
"A" => Self::from(6.02214076e23), "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) // Planck's constant, in J*s (joule-seconds)
"h" => Self::from(6.62607015e-34), "h" => Self::from(6.62607015e-34),
"e" => Self::from(f64::consts::E), "e" => Self::from(f64::consts::E),

View file

@ -51,3 +51,8 @@ fn constant_implicit_mult() {
assert_eq!(eval("2pi"), 6.283185307179586); assert_eq!(eval("2pi"), 6.283185307179586);
assert_eq!(eval("pi2"), 6.283185307179586); assert_eq!(eval("pi2"), 6.283185307179586);
} }
#[test]
fn pi_precision() {
assert_eq!(eval("sin(pi)"), 0.)
}