@@ -7,12 +7,24 @@ A mathematical expression evaluator library written in Rust with support for cus
77## Features
88
99- ** Mathematical expressions** - Arithmetic, comparisons, and built-in functions
10- - ** 128-bit decimal precision ** - No floating-point errors using ` rust_decimal `
10+ - ** Flexible numeric types ** - Choose between fast f64 (default) or high-precision 128-bit Decimal
1111- ** Custom symbols** - Register your own constants and functions
1212- ** Rich error messages** - Syntax errors with source location highlighting
1313- ** Bytecode compilation** - Compile expressions to portable binary format
1414- ** Stack-based VM** - Efficient execution on a virtual machine
1515
16+ ## What's it For?
17+
18+ Need to evaluate math but don't want to embed an entire scripting language? You're in the right place. 🎯
19+
20+ ** Perfect for:**
21+ - ** Game engines** - Calculate damage formulas, level requirements, or item stats without hardcoding values
22+ - ** Configuration files** - Let users write ` price * 0.9 ` instead of forcing them to update every value manually
23+ - ** Analytics dashboards** - Enable power users to define custom metrics: ` (revenue - cost) / users `
24+ - ** Form calculators** - Mortgage calculators, unit converters, or any user-facing math
25+ - ** Educational tools** - Math tutoring apps, graphing calculators, or homework helpers
26+ - ** Learning compilers** - Clean example of lexer, parser, and stack-based VM in ~ 2K lines of Rust
27+
1628## How It Works
1729
1830Classic compiler pipeline with type-safe state transitions:
@@ -33,7 +45,35 @@ Add this to your `Cargo.toml`:
3345
3446``` toml
3547[dependencies ]
36- expr-solver-lib = " 1.1.1"
48+ expr-solver-lib = " 1.2.0"
49+ ```
50+
51+ ** Numeric Type Selection:**
52+
53+ The library supports two numeric backends via feature flags (mutually exclusive):
54+
55+ - ** ` f64-floats ` ** (default) - Standard f64 floating-point arithmetic. Faster and simpler, allows Inf and NaN results.
56+ - ** ` decimal-precision ` ** - 128-bit Decimal for high precision. No floating-point errors, checked arithmetic with overflow detection.
57+
58+ To use high-precision Decimal:
59+
60+ ``` toml
61+ [dependencies ]
62+ expr-solver-lib = { version = " 1.2.0" , default-features = false , features = [" decimal-precision" ] }
63+ ```
64+
65+ To enable bytecode serialization with f64:
66+
67+ ``` toml
68+ [dependencies ]
69+ expr-solver-lib = { version = " 1.2.0" , features = [" serialization" ] }
70+ ```
71+
72+ To enable bytecode serialization with Decimal:
73+
74+ ``` toml
75+ [dependencies ]
76+ expr-solver-lib = { version = " 1.2.0" , default-features = false , features = [" decimal-precision" , " serialization" ] }
3777```
3878
3979### As a binary
@@ -42,7 +82,7 @@ Add this to your `Cargo.toml`:
4282
4383``` toml
4484[dependencies ]
45- expr-solver-bin = " 1.1.1 "
85+ expr-solver-bin = " 1.2.0 "
4686```
4787
4888### Quick Evaluation
@@ -60,52 +100,83 @@ let result = eval("sqrt(16) + sin(pi/2)").unwrap();
60100
61101### Custom Symbols
62102
103+ ``` rust
104+ use expr_solver :: {eval_with_table, SymTable , Number , ParseNumber };
105+
106+ let mut table = SymTable :: stdlib ();
107+ table . add_const (" x" , Number :: parse_number (" 10" ). unwrap ()). unwrap ();
108+ table . add_func (" double" , 1 , false , | args | {
109+ Ok (args [0 ] * Number :: parse_number (" 2" ). unwrap ())
110+ }). unwrap ();
111+
112+ let result = eval_with_table (" double(x)" , table ). unwrap ();
113+ assert_eq! (result . to_string (), " 20" );
114+ ```
115+
116+ Or with f64 (default):
117+
63118``` rust
64119use expr_solver :: {eval_with_table, SymTable };
65- use rust_decimal_macros :: dec;
66120
67121let mut table = SymTable :: stdlib ();
68- table . add_const (" x" , dec! ( 10 ) ). unwrap ();
69- table . add_func (" double" , 1 , false , | args | Ok (args [0 ] * dec! ( 2 ) )). unwrap ();
122+ table . add_const (" x" , 10.0 ). unwrap ();
123+ table . add_func (" double" , 1 , false , | args | Ok (args [0 ] * 2.0 )). unwrap ();
70124
71125let result = eval_with_table (" double(x)" , table ). unwrap ();
72- assert_eq! (result , dec! ( 20 ) );
126+ assert_eq! (result , 20.0 );
73127```
74128
75129### Compile Once, Execute Many Times
76130
77131``` rust
78- use expr_solver :: {load, SymTable };
79- use rust_decimal_macros :: dec;
132+ use expr_solver :: {Program , SymTable };
80133
81134// Compile expression
82- let program = load (" x * 2 + y" ). unwrap ();
135+ let program = Program :: new_from_source (" x * 2 + y" ). unwrap ();
83136
84137// Execute with different values
85138let mut table = SymTable :: new ();
86- table . add_const (" x" , dec! ( 10 ) ). unwrap ();
87- table . add_const (" y" , dec! ( 5 ) ). unwrap ();
139+ table . add_const (" x" , 10.0 ). unwrap ();
140+ table . add_const (" y" , 5.0 ). unwrap ();
88141
89142let linked = program . link (table ). unwrap ();
90- let result = linked . execute (). unwrap (); // 25
143+ let result = linked . execute (). unwrap (); // 25.0
144+ assert_eq! (result , 25.0 );
91145```
92146
93- ## Precision
147+ ## Numeric Precision
148+
149+ The library supports two numeric backends:
94150
95- Uses ** 128-bit ` Decimal ` ** arithmetic for exact decimal calculations without floating-point errors.
151+ ### f64 (Default)
152+ - Standard IEEE 754 double-precision floating-point
153+ - Fast and efficient for most use cases
154+ - Allows ` Inf ` and ` NaN ` results (e.g., ` 1/0 ` → ` Inf ` , ` sqrt(-1) ` → ` NaN ` )
155+ - Minimal error checking - only prevents panics
156+
157+ ### Decimal (Optional)
158+ - 128-bit fixed-point arithmetic via ` rust_decimal `
159+ - Exact decimal representation (no 0.1 + 0.2 ≠ 0.3 issues)
160+ - Checked arithmetic with overflow/underflow detection
161+ - Domain validation (e.g., ` sqrt(-1) ` returns an error)
162+ - Ideal for financial calculations or when exact decimal precision is required
163+
164+ ** Choosing the right mode:**
165+ - Use ** f64** (default) for general-purpose math, scientific computing, or when performance is critical
166+ - Use ** Decimal** for financial applications, accounting, or when exact decimal representation is required
96167
97168## Built-in Functions
98169
99170| Category | Functions |
100171| ----------------| ---------------------------------------------------------------------------|
101172| ** Arithmetic** | ` abs ` , ` sign ` , ` floor ` , ` ceil ` , ` round ` , ` trunc ` , ` fract ` , ` mod ` , ` clamp ` |
102- | ** Trig** | ` sin ` , ` cos ` , ` tan ` , ` asin ` * , ` acos ` * , ` atan ` * , ` atan2 ` * |
103- | ** Hyperbolic** | ` sinh ` * , ` cosh ` * , ` tanh ` * |
104- | ** Exp/Log** | ` sqrt ` , ` cbrt ` * , ` pow ` , ` exp ` , ` exp2 ` * , ` log ` , ` log2 ` * , ` log10 ` , ` hypot ` * |
173+ | ** Trig** | ` sin ` , ` cos ` , ` tan ` , ` asin ` , ` acos ` , ` atan ` , ` atan2 ` |
174+ | ** Hyperbolic** | ` sinh ` , ` cosh ` , ` tanh ` |
175+ | ** Exp/Log** | ` sqrt ` , ` cbrt ` , ` pow ` , ` exp ` , ` exp2 ` , ` log ` , ` log2 ` , ` log10 ` , ` hypot ` |
105176| ** Variadic** | ` min ` , ` max ` , ` sum ` , ` avg ` (1+ args) |
106177| ** Special** | ` if(cond, then, else) ` |
107178
108- \* * Uses f64 internally, may have minor precision differences *
179+ > ** Note: ** In ` decimal-precision ` mode, some operations (inverse trig, ` pow ` ) use internal f64 conversion due to ` rust_decimal ` limitations, which may introduce small precision loss.
109180
110181## Built-in Constants
111182
@@ -153,8 +224,14 @@ expr-solver -t
153224Run the test suite:
154225
155226``` bash
156- # Run all tests
227+ # Run all tests with default f64 mode
157228cargo test
229+
230+ # Test with decimal-precision mode
231+ cargo test -p expr-solver-lib --no-default-features --features decimal-precision
232+
233+ # Test binary with f64 mode
234+ cargo test -p expr-solver-bin
158235```
159236
160237## License
0 commit comments