用自定义脚本函数评估数学表达式

3
我正在寻找一种算法或方法来评估以字符串形式表示的数学表达式。该表达式包含数学组件,但也包含自定义函数。我希望在C#/.Net中实现该算法。
我知道Roslyn允许我评估以下类型的表达式:
"var value = 3+5*11-Math.Sqrt(9);"
我也熟悉如何使用"节点重写"来避免变量声明或完全限定的函数名称,或省略尾随分号以便评估
"value = 3+5*11-Sqrt(9)"
然而,我想在此基础上实现自定义脚本函数,例如:
"value = Ratio(A,B)",其中Ratio是一个自定义函数,它将向量A中的每个元素除以向量B中的每个元素,并返回一个相同长度的向量。
或者
"value = Sma(A, 10)",其中Sma是一个自定义函数,它计算具有10个回顾窗口的向量/时间序列A的简单移动平均值。
理想情况下,我希望能够提供更复杂的功能,例如:
"value = Ratio(A,B) * Pi + 0.5 * Spread(C,D) + Sma(E, lookback)",其中解析引擎将尊重运算符优先级,并构建解析树以获取必要的值来评估表达式。
我无法想象如何能够使用Roslyn解决这类问题。
还有哪些方法可以让我开始,或者我是否错过了Roslyn提供的可能有助于解决此问题的功能?

请看 https://github.com/mariuszgromada/MathParser.org-mXparser。它符合您的所有要求,除了基本的方程求解外,它还包括添加用户定义函数/常量/参数等的能力,并支持许多内置函数。通过 Function ratio = new Function("ratio(x,y) = x/y"); f.calculate(1,2); Expression e = new Expression("Ratio(A,B) * Pi + 0.5 * Spread(C,D) + Sma(E, lookback)", f); 即可完成。而且Pi已经被定义过了! - degant
谢谢,我会查看。 - Matt
除了关于mXparser的提示之外,还可以通过mXparser教程进行学习:http://mathparser.org/mxparser-tutorial/ - Leroy Kegan
谢谢,最终我选择了Roslyn,因为它提供了我所需的一切。 - Matt
1个回答

5
假设您的所有表达式都是有效的C#表达式,您可以以多种方式使用Roslyn。
你可以仅使用Roslyn进行解析。SyntaxFactory.ParseExpression将为您提供表达式的语法树。请注意,您的第一个(var v = expr;)示例不是表达式,而是变量声明。但是,v = expr是一个表达式,即AssignmentExpressionSyntax。然后,您可以遍历此AST,并对每个节点执行您想要执行的操作,基本上您将编写一个解释器。这种方法的好处是您无需编写自己的解析器,遍历AST非常简单,这种方法非常灵活,因为定义如何处理“未知”方法完全取决于您。
也可以使用Roslyn进行评估。可以通过多种方式完成:组合有效的C#文件并将其编译为程序集,或者可以使用Scripting API。这种方法基本上需要一个包含所有额外方法实现的类库,例如SmaSpread等。但是在第一种方法中也需要以某种形式使用它们,因此这并不是真正的额外工作。
如果唯一的目标是评估表达式,那么我会选择第二种方法。如果有额外的要求(你没有提到),比如能够生成一个简化的表达式形式,那么我会考虑第一种解决方案。
如果你找到了一个完全符合你需求的库(性能好,你不介意依赖第三方工具...),那么我会选择它。评论中提到的MathParser.org-mXparser似乎正是你所寻找的。

很好,我猜我需要更多地了解Roslyn的语法树功能。 - Matt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接