2016-04-22 69 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()你感興趣的值