A fast, safe mathematical expression parser and evaluator for Rust.
- Fast - Compiles expressions to bytecode for efficient repeated evaluation (~15-80ns per eval)
- Safe - No unsafe code, proper error handling
no_stdcompatible - Works in embedded environments withalloc- Rich function library - 27 built-in functions including trig, logarithms, rounding, and more
use mathexpr::Expression;
// Parse, compile, and evaluate
let expr = Expression::parse("sqrt(x^2 + y^2)")?
.compile(&["x", "y"])?;
assert_eq!(expr.eval(&[3.0, 4.0])?, 5.0);
assert_eq!(expr.eval(&[5.0, 12.0])?, 13.0);For simple cases where you don't need to reuse the compiled expression:
use mathexpr::eval;
let result = eval("2 * pi * r", &["r"], &[5.0])?;
// result ≈ 31.4159Use _ to reference an input value, useful for transformations:
use mathexpr::Expression;
let normalize = Expression::parse("(_ - min) / (max - min)")?
.compile(&["min", "max"])?;
// Normalize 50 to range [0, 100]
let result = normalize.eval_with_current(50.0, &[0.0, 100.0])?;
assert_eq!(result, 0.5);| Operator | Description | Precedence |
|---|---|---|
+, - |
Addition, Subtraction | Lowest |
*, /, % |
Multiplication, Division, Modulo | Medium |
^ |
Exponentiation (right-associative) | Highest |
-x |
Unary negation | Highest |
| Function | Description |
|---|---|
abs(x) |
Absolute value |
sqrt(x) |
Square root |
cbrt(x) |
Cube root |
exp(x) |
Exponential (e^x) |
log(x), ln(x) |
Natural logarithm |
log2(x) |
Base-2 logarithm |
log10(x) |
Base-10 logarithm |
pow(base, exp) |
Power |
mod(a, b) |
Modulo |
min(a, b) |
Minimum |
max(a, b) |
Maximum |
clamp(x, min, max) |
Clamp to range |
| Function | Description |
|---|---|
sin(x), cos(x), tan(x) |
Basic trig |
asin(x), acos(x), atan(x) |
Inverse trig |
sinh(x), cosh(x), tanh(x) |
Hyperbolic |
| Function | Description |
|---|---|
floor(x) |
Round down |
ceil(x) |
Round up |
round(x) |
Round to nearest |
trunc(x) |
Truncate toward zero |
signum(x) |
Sign (-1, 0, or 1) |
| Constant | Description |
|---|---|
pi or pi() |
π ≈ 3.14159... |
e or e() |
Euler's number ≈ 2.71828... |
mathexpr provides three error types:
use mathexpr::{Expression, ParseError, CompileError, EvalError};
// Parse errors - invalid syntax
match Expression::parse("@#$") {
Err(ParseError::InvalidSyntax(msg)) => { /* handle */ }
Err(ParseError::UnexpectedTrailingInput(s)) => { /* handle */ }
_ => {}
}
// Compile errors - undefined variables or unknown functions
match Expression::parse("x + y")?.compile(&["x"]) {
Err(CompileError::UndefinedVariable(name)) => { /* handle */ }
Err(CompileError::UnknownFunction(name)) => { /* handle */ }
Err(CompileError::WrongArity { name, expected, got }) => { /* handle */ }
_ => {}
}
// Eval errors - runtime errors
match expr.eval(&[0.0]) {
Err(EvalError::DivisionByZero) => { /* handle */ }
_ => {}
}Note: Domain errors (like sqrt(-1)) return NaN rather than errors.
Typical evaluation times on modern hardware:
| Expression Complexity | Time per Eval |
|---|---|
Simple (a + b) |
~15 ns |
Medium (sqrt(x^2 + y^2)) |
~25 ns |
| Complex (5+ functions) | ~60-80 ns |
Run the included examples:
# Basic API usage
cargo run --example basic
# Error handling patterns
cargo run --example errors
# Interactive calculator with history
cargo run --example repl| Feature | Description |
|---|---|
std (default) |
Enables std::error::Error implementations |
For no_std environments:
[dependencies]
mathexpr = { version = "0.1", default-features = false }Requires the alloc crate.
MIT License. See LICENSE for details.