如何解析一次数学函数并多次使用其结果

时间:2016-04-22 18:01:27

标签: java parsing

我打算编写一个程序来计算给定函数的零点。我决定编写一个解析器来解析该函数​​(我之前从未写过)。它是像"sin(1/x)+exp(x)"这样的实变量的实值函数。我想使用像Bisection和Newton这样的根查找方法。由于这些方法是迭代的,我想避免每次在每个点x的循环中评估函数。所以在我努力编写自己的解析器之前,我想知道可以解析一次并在点f评估函数x0, x2, ..., xn而无需为每个解析f x

3 个答案:

答案 0 :(得分:2)

这个问题有两种标准方法:

  1. 将公式解析为所谓的"抽象语法树" (AST)。这是一个表示公式结构的编译器数据结构,可以通过代码快速检查。也可以相对快速地将AST评估为公式。看到我的答案 构建支持上述任务的递归下降解析器: Is there an alternative for flex/bison that is usable on 8-bit embedded systems?

  2. 以某种方式将公式编译成您的编程语言。这通常涉及首先构建AST,然后将AST转换为编程语言术语,在该结果上运行编译器,然后加载编译结果。使用C等编译语言可能会很尴尬,因为缺少动态链接;使用Java或C#等语言更容易,因为它们鼓励动态加载。 您可以猜测,这种方法需要付出更多的努力,但现在可以通过编程语言尽快评估公式。您可以通过临时(例如,递归下降)解析和翻译来完成此操作,或者您可以使用重写"工具以更加规律的方式解决此问题。一种语法到另一种:https://softwarerecs.stackexchange.com/a/31379/101

答案 1 :(得分:1)

正如Ira已经指出的那样,您将表达式解析为抽象语法树。适合您的抽象语法树看起来类似于:

interface AstNode {
  double eval(double x);
}

class ConstantNode implements AstNode {
  double value;

  double eval(double x) {
    return value;
  }
}

class VariableNode implements AstNode {
  double eval(double x) {
    return x;
  }
}

class OperatorNode implements AstNode {
  char op;
  AstNode left;
  AstNode right;

  double eval(double x) {
    switch (op) {
      case '+': return left.eval(x) + right.eval(x);
      case '-': return left.eval(x) - right.eval(x);
      case '/': return left.eval(x) / right.eval(x);
      case '*': return left.eval(x) * right.eval(x);
      case '^': return Math.pow(left.eval(x), right.eval(x));
      default:
        throw new RuntimeException("Invalid op " + op);
    }
  }
}

class Function implements AstNode {
  ...

将表达式解析为树后,只需使用您感兴趣的值调用eval()即可。

答案 2 :(得分:0)

也许你可以用Java Scripting Support做到这一点。例如,应该可以在Javascript(Nashorn)中评估函数。

亲:你不需要自己解析这个功能。只需提供脚本API。