Skip to content

轻量的C++数值计算库,支持高度自定义的表达式解析与计算

Notifications You must be signed in to change notification settings

ydog01/cxx_eval

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

54 Commits
 
 
 
 
 
 
 
 

Repository files navigation

** 🇨🇳 中文文档 **

C++ Mathematical Expression Evaluator

A powerful, header-only C++ library for parsing and evaluating mathematical expressions C++11 Header-Only

✨ Features

Header-only – Zero compilation overhead, easy integration
Type Flexible – Works with any numeric type (double, float, int, etc.)
Character Support – Full support for narrow (char) and wide (wchar_t) strings
Variable Management – Register variables with const/mutable semantics
Operator Control – Define custom operators with precedence and associativity
Function Library – Extensive built-in mathematical functions
Expression Parsing – Three parsing modes: Immediate, Persistent, Normal
Constant Folding – Automatically optimizes constant subexpressions
Custom Functions – Define new functions using expression strings
Smart Memory – RAII-compliant with shared_ptr/weak_ptr support

🔧 Requirements

• C++11 or later
• Standard Template Library (STL)
• No external dependencies

📥 Installation

  1. Download eval.hpp and table.hpp
  2. Place them in your project's include directory
  3. Include eval.hpp in your source files
  4. Compile with C++11 support enabled
#include "eval.hpp" 

🚀 Quick Start

Basic Arithmetic

#include "eval.hpp" 
#include <iostream> 
int main() 
{ 
    using Evaluator = cxx_eval::basic_eval<char, double>::Evaluator; 
    using Simple = cxx_eval::basic_eval<char, double>::simple; 
    Evaluator eval; 
    Simple::setup_allmath(eval); 
    Simple::register_vars(eval, "x", 10.0); 
    auto expr = eval.parse<false>("2 * x + 3.14"); 
    double result = expr.evaluate(); 
    std::cout << "Result: " << result << std::endl; // 23.14 
    return 0; 
} 

With Variables

Simple::register_vars(eval, "a", 5.0, "b", 3.0, "c", 2.0); 
auto expr = eval.parse<false>("a * b + c"); 
std::cout << expr.evaluate() << std::endl; // 17.0 
auto var_node = eval.get_variables()->find_seq("a"); 
var_node->get_data()->data = 10.0; 
std::cout << expr.evaluate() << std::endl; // 32.0 

📚 Documentation

See below for full documentation, API reference, and advanced examples.

🧠 Core Concepts

Expression Structure

The library uses a postfix (RPN) representation internally:
c – Constant value
v – Variable reference
f – Function/operator application

Parsing Modes

Immediate – All values become constants (optimization)
Persistent – All values remain variables (uses weak_ptr)
Normal – Respects const/mutable declarations

Operator Precedence

Higher precedence numbers bind tighter. Default precedences:
• Assignment (=) – 0
• Addition/Subtraction (+, -) – 1
• Multiplication/Division (*, /, %) – 2
• Exponentiation (^) – 3
• Unary operators – 2
• Functions – size_max (highest)

📖 API Reference

Evaluator Class

Construction & Setup

cxx_eval::basic_eval<char, double>::Evaluator eval; 
 eval.set_skip([](char c) { return c == ' '; }); 
eval.enable_whitespace_skip(true); 
eval.set_left_delimiter('('); 
eval.set_right_delimiter(')'); 
eval.set_cut_delimiter(','); 
evaluator.enable_brackets(true);
evaluator.enable_cut(true);

Variable Management

Simple::register_vars(eval, "var1", 1.0, "var2", 2.0); 
Simple::register_consts(eval, "PI", 3.14159); 
auto vars = eval.get_variables(); 
auto node = vars->find_seq("var1"); 
if (node && node->has_data()) 
{ 
    double value = node->get_data()->data; 
} 

Operator Registration

Simple::register_infix(eval, "**", [](std::shared_ptr<RootVar>* args) 
{ 
    ConstVar result; 
    result.data = std::pow(args[0]->data, args[1]->data); 
    return std::make_shared<ConstVar>(result); 
}, 3); 
Simple::register_prefix(eval, "
", [](std::shared_ptr<RootVar>* args) 
{ 
    ConstVar result; 
    result.data = -args[0]->data; 
    return std::make_shared<ConstVar>(result); 
}, 2); 
Simple::register_function(eval, "max", [](std::shared_ptr<RootVar>* args) 
{ 
    ConstVar result; 
    result.data = std::max(args[0]->data, args[1]->data); 
    return std::make_shared<ConstVar>(result); 
}, 2); 

Custom Functions from Expressions

Simple::register_function<false>(eval, "f", std::vector<std::string>{"x", "y"}, "x^2 + y^2"); 
auto expr = eval.parse<false>("f(3,4)"); 
std::cout << expr.evaluate() << std::endl; // 25.0 

Expression Template

auto expr = eval.parse<false>("2 + 2"); 
double result = expr.evaluate(); 
auto persistent = eval.parse<true>("x + y"); 

🎯 Advanced Examples

Custom Mathematical Constants

Simple::register_consts(eval, "e", 2.718281828459045); 
Simple::register_consts(eval, "phi", 1.618033988749895); 

Complex Function Definition

Simple::register_function<false>(eval, "quadratic", std::vector<std::string>{"a", "b", "c"}, "(-b + sqrt(b^2 - 4*a*c)) / (2*a)"); 
auto expr = eval.parse<false>("quadratic(1, -5, 6)"); 
std::cout << expr.evaluate() << std::endl; // 3.0 

Assignment Operator

Simple::setup_assignment(eval); 
auto expr = eval.parse<false>("x = 42"); 
expr.evaluate(); 
auto check = eval.parse<false>("x"); 
std::cout << check.evaluate() << std::endl; // 42 

Wide Character Support

using WEvaluator = cxx_eval::basic_eval<wchar_t, double>::Evaluator; 
using WSimple = cxx_eval::basic_eval<wchar_t, double>::simple; 
WEvaluator weval; 
WSimple::setup_allmath(weval); 
WSimple::register_vars(weval, L"变量", 3.14); 
auto wexpr = weval.parse<false>(L"变量 * 2"); 
std::wcout << wexpr.evaluate() << std::endl; 

Custom Skip Behavior

eval.set_skip([](char c) 
{ 
    return !std::isalnum(c) && c != '+' && c != '-' && c != '*' && c != '/' && c != '^' && c != '(' && c != ')'; 
}); 
eval.enable_whitespace_skip(true); 

🔨 Customization

Implementing Custom Numeric Types

struct Complex 
{ 
    double real, imag; 
    Complex operator+(const Complex& other) const 
    { 
        return {real + other.real, imag + other.imag}; 
    } 
}; 
using ComplexEval = cxx_eval::basic_eval<char, Complex>::Evaluator; 
using ComplexSimple = cxx_eval::basic_eval<char, Complex>::simple; 

Custom Constant Parser

eval.set_constant_parser([](const std::string& str, std::size_t& pos, std::string& structure, std::vector<cxx_eval::basic_eval<char, double>::ConstVar>& constants) -> bool 
{ 
    if (str.substr(pos, 2) == "0x") 
    { 
        // Parse hexadecimal logic 
        return true; 
    } 
    return false; 
}); 

⚠️ Error Handling

The library throws std::runtime_error for:
• Syntax errors
• Undefined variables
• Mismatched parentheses
• Stack underflow/overflow
• Expired weak_ptr access

try 
{ 
    auto result = expr.evaluate(); 
} 
catch (const std::runtime_error& e) 
{ 
    std::cerr << "Evaluation error: " << e.what() << std::endl; 
} 

🤝 Contributing

Contributions welcome! Submit pull requests or open issues for bugs and feature requests.

About

轻量的C++数值计算库,支持高度自定义的表达式解析与计算

Topics

Resources

Stars

Watchers

Forks

Languages