2016-04-22 65 views
1

我将编写一个计算给定函数的零的程序。我决定写一个解析器来解析这个函数(我从来没有写过)。它是一个真实变量的实值函数,如"sin(1/x)+exp(x)"。我想使用像Bisection和Newton这样的查找方法。由于这些方法是迭代的,因此我希望避免每次在每个点的循环中评估函数x。因此,在我努力编写我自己的解析器之前,我想知道是否可以仅解析一次,并在点x0, x2, ..., xn处评估函数f,而不必为每个x重新解析f如何解析一次数学函数并多次使用其结果

+0

你可以存储地图。其中'x'映射到'f(x)'。 – vikingsteve

回答

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

+0

我不能得到第二部分,你的意思是把函数解析成Java代码,把它放到一个类中,保存为'.java'文件,编译并加载它? – Dante

+1

是的..挑剔,你不“解析功能到Java代码”。您解析公式来构建代表它所说的数据结构(AST)。然后,您将构建一个小型翻译器,用于遍历这些数据结构并发出Java代码。 (或C,或任何你的编程语言)。 –

0

也许你可以使用Java脚本支持来做到这一点。例如,应该可以在Javascript(Nashorn)中评估函数。

Pro:你不需要自己解析函数。只需提供脚本API。

1

由于艾拉有已经指出,您将您的表达式解析为抽象语法树。抽象语法树适合您将类似于此:

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()你感兴趣的值