提问人:FusRoDah 提问时间:7/14/2023 更新时间:7/14/2023 访问量:109
存储数学表达式以进行计算的有效方法是什么?
What is an efficient way to store mathematical expressions for evaluation?
问:
我的目标是编写一个程序,可以解析包括变量在内的数学表达式 - 如“x^2+3y+sin(x)” - 然后在给定其值时计算它们(因此对于 x=0,y=1,输出将为 3)。
解析本身没有问题 - 我使用了调车场算法的一个版本,它运行良好。但是,我现在正在考虑如何以一种易于评估的方式存储输出。
一种方法是简单地将表达式中的所有变量替换为其值,然后对其进行计算。如果表达式被计算一次就好了 - 但是,我希望会有一个表达式,并且会插入许多不同的值。因此,我想找到一种方法来存储解析的表达式,以便快速替换变量并对其进行计算,并且具有合理的内存效率。有什么想法吗?
我想到的一种方法是将表达式存储为反向波兰符号的标记数组,可以有效地进行评估。
可能看起来像这样:Token
enum TokenType {NUMBER, VARIABLE, OPERATOR, FUNCTION};
struct Token
{
TokenType type;
union
{
int value; // if type = NUMERIC
int variable_index; // if type = VARIABLE
operator_params op; // if type = OPERATOR
function_params fun; // if type = FUNCTION
}
}
变量值可以在一个简单的数组中进行排序,并由 的 访问 。当值发生变化时,我们只需更新变量值数组 - 表达式保持不变。variable index
Token
我不确定存储此应用程序的运算符和函数的最佳方式是什么。我的想法是有一个指向正确操作的函数指针,但我不确定这是否是最好的方法。
答:
按 RPN 顺序对令牌进行排序是一种方法,并且性能非常高。 标记可以是文字、变量或运算符。若要计算表达式,请按顺序处理标记,如果是文本或变量,则将其值推送到堆栈。如果是操作,则从堆栈中弹出一个或两个项目(取决于它是一元运算符还是二进制运算符),对这些项目应用操作,然后将结果推送回去。对于格式正确的表达式,最后在堆栈上将留下一个值,这是计算的最终结果。
另一种有效的方法是创建嵌套的 lambda 表达式,正如我在这篇 CodeReview 文章中所展示的那样。这样做的主要优点是解析表达式的结果是一个 lambda 函数,其工作方式与 C++ 中的常规函数几乎相同。
评论
x
y
class Expression { public: virtual Expression() = default; virtual double operator()(double* vars) = 0; };