Crate exmex[−][src]
Expand description
Exmex is a fast extendable mathematical expression evaluator.
use exmex::{eval_str}; assert!((eval_str("1.5 * ((cos(0) + 23.0) / 2.0)")? - 18.0).abs() < 1e-12);
For floats, we have a list of predifined operators, namely
^
, *
, /
, +
, -
, sin
, cos
, tan
, exp
, log
, and log2
. These are
defined in make_default_operators
.
Variables
For variables we can use curly brackets as shown in the following expression.
Variables’ values are passed as slices to eval
.
use exmex::{make_default_operators, parse}; let to_be_parsed = "log({x}) + 2* (-{x}^2 + sin(4*{y}))"; let expr = parse::<f64>(to_be_parsed, make_default_operators::<f64>())?; assert!((expr.eval(&[2.5, 3.7]) - 14.992794866624788 as f64).abs() < 1e-12);
The n
-th number in the slice corresponds to the n
-th variable. Thereby only the
first occurence of the variables is relevant. In this example, we have x=2.5
and y=3.7
.
Extendability
Library users can also define a different set of operators as shown in the following.
use exmex::{parse, BinOp, Operator}; let ops = vec![ Operator { repr: "%", bin_op: Some(BinOp{op: |a: i32, b: i32| a % b, prio: 1}), unary_op: None, }, Operator { repr: "/", bin_op: Some(BinOp{op: |a: i32, b: i32| a / b, prio: 1}), unary_op: None, }, ]; let to_be_parsed = "19 % 5 / 2"; let expr = parse::<i32>(to_be_parsed, ops)?; assert_eq!(expr.eval(&[1, 0]), 2);
Operators
Operators are instances of the struct
Operator
that has its representation in the field
repr
, a binary and a unary operator of
type Option<BinOp<T>>
and
Option<fn(T) -> T>
, respectively, as
members. BinOp
contains in addition to the operator op
of type fn(T, T) -> T
an
integer prio
. Operators
can be both, binary and unary such as -
as defined in the list of default
operators. Note that we expect a unary operator to be always on the left of a
number.
Data Types of Numbers
You can use any type that implements Copy
and
FromStr
. In case you do not pass a number that matches the
regex r"\.?[0-9]+(\.[0-9]+)?"
, you have to pass a suitable regex and use the
function parse_with_number_pattern
instead of
parse
. Here is an example for bool
.
use exmex::{parse_with_number_pattern, BinOp, Operator}; let ops = vec![ Operator { repr: "&&", bin_op: Some(BinOp{op: |a: bool, b: bool| a && b, prio: 1}), unary_op: None, }, Operator { repr: "||", bin_op: Some(BinOp{op: |a: bool, b: bool| a || b, prio: 1}), unary_op: None, }, Operator { repr: "!", bin_op: None, unary_op: Some(|a: bool| !a), }, ]; let to_be_parsed = "!(true && false) || (!false || (true && false))"; let expr = parse_with_number_pattern::<bool>(to_be_parsed, ops.clone(), "true|false")?; assert_eq!(expr.eval(&[]), true);
Priorities and Parentheses
In Exmex-land, unary operators always have higher priority than binary operators, e.g.,
-2^2=4
instead of -2^2=-4
. Moreover, we are not too strict regarding parentheses.
For instance "---1"
will evalute to -1
.
If you want to be on the safe side, we suggest using parentheses.
Structs
A binary operator that consists of a function pointer and a priority.
This will be thrown at you if the parsing went wrong. Ok, obviously it is not an exception, so thrown needs to be understood figuratively.
This is the core data type representing a flattened expression and the result of
parsing a string. The expression is flattened to make efficient evaluation possible.
Simplified, it consists of a SmallVec
of nodes and a
SmallVec
of operators that are applied to the nodes in an order following
operator priorities.
Operators can be custom-defined by the library-user in terms of this struct.
Functions
Parses a string, evaluates a string, and returns the resulting number.
Returns the default operators.
Parses a string and a vector of operators into an expression that can be evaluated.
Parses a string into an expression that can be evaluated using default operators.
Parses a string and a vector of operators and a regex pattern that defines the looks of a number into an expression that can be evaluated.