数学パーサー

みんなありがとう! この記事には必要な数の利点があり、著者も加わりました! ここにあります: elw00d

私は仲間のアフィリエイトに自分の文章のライブラリを提示します。これを使用すると、簡単な数学関数を簡単に処理し、文字列形式の挿入記法から後置記法で構成された処理済み表現に変換することができます。 なぜこれが必要なのでしょうか?



たとえば、ユーザー入力を文字列として受け入れ、構文を分析し、指定されたポイントでその値を計算し、入力式を最適化し、計算に必要な操作の数を最小化し、結果を文字列として生成できるアプリケーションを作成できます最適化された関数の文字列表現。 特定のアプリケーションとして、さまざまな専門の計算機(プログラム可能なもののように構築されたものを含む)、初期機能の設定を必要とするグラフまたはその他のレポートの構築に使用されるアプリケーション、またはスパム/自動登録に対する保護を構築するためのオリジナルツールとして注目できます。



それはすべて、数値最適化手法の実験室作業のために、スーパープログラマーによって書かれた手動のアプリケーションを見たという事実から始まりました。 その中の元の関数の入力は次の元の方法で編成されました:ユーザー(==学生)は関数を導入し、プログラムはソースを生成し、その隣にあるDelphiコンパイラを実行してDLLを取得しました。 次に、表示されたDLLがプログラムにロードされ、関数に従ってグラフが作成されました。 開発者の独創性を少し笑っていると思いましたが、Delphiコンパイラのような厚い「プラグイン」を使用せずに、同様の機能をどのように整理できるのでしょうか。 その結果、このようなタスク用に独自のパーサーを作成するというアイデアを得ました。 これがこのアイデアから生まれたものです。



現時点では、次の機能が実装およびテストされています。



1.標準の数学演算子+、-、/、*、関数で構成される式の文字列の分析

sin、cos、かっこ。 変数は、構文に受け入れられる任意の名前でサポートされます

アナライザー(文字と数字で構成され、文字で始まる必要があります)。



このような式の例は文字列です

-4 + 5.5 * sin(1/3)*(2 + 5) 」。



この式を計算するには、コードを記述する必要があります。

// PreparedExpression preparedExpression = ToolsHelper.Parser.Parse( "-4+5.5*sin(1/3)*(2+5)" ); CompiledExpression compiledExpression = ToolsHelper.Compiler.Compile(preparedExpression); // , // , List <VariableValue> variables = new List <VariableValue>(); // double res = ToolsHelper.Calculator.Calculate(compiledExpression, variables); * This source code was highlighted with Source Code Highlighter .



  1. // PreparedExpression preparedExpression = ToolsHelper.Parser.Parse( "-4+5.5*sin(1/3)*(2+5)" ); CompiledExpression compiledExpression = ToolsHelper.Compiler.Compile(preparedExpression); // , // , List <VariableValue> variables = new List <VariableValue>(); // double res = ToolsHelper.Calculator.Calculate(compiledExpression, variables); * This source code was highlighted with Source Code Highlighter .



  2. // PreparedExpression preparedExpression = ToolsHelper.Parser.Parse( "-4+5.5*sin(1/3)*(2+5)" ); CompiledExpression compiledExpression = ToolsHelper.Compiler.Compile(preparedExpression); // , // , List <VariableValue> variables = new List <VariableValue>(); // double res = ToolsHelper.Calculator.Calculate(compiledExpression, variables); * This source code was highlighted with Source Code Highlighter .



  3. // PreparedExpression preparedExpression = ToolsHelper.Parser.Parse( "-4+5.5*sin(1/3)*(2+5)" ); CompiledExpression compiledExpression = ToolsHelper.Compiler.Compile(preparedExpression); // , // , List <VariableValue> variables = new List <VariableValue>(); // double res = ToolsHelper.Calculator.Calculate(compiledExpression, variables); * This source code was highlighted with Source Code Highlighter .



  4. // PreparedExpression preparedExpression = ToolsHelper.Parser.Parse( "-4+5.5*sin(1/3)*(2+5)" ); CompiledExpression compiledExpression = ToolsHelper.Compiler.Compile(preparedExpression); // , // , List <VariableValue> variables = new List <VariableValue>(); // double res = ToolsHelper.Calculator.Calculate(compiledExpression, variables); * This source code was highlighted with Source Code Highlighter .



  5. // PreparedExpression preparedExpression = ToolsHelper.Parser.Parse( "-4+5.5*sin(1/3)*(2+5)" ); CompiledExpression compiledExpression = ToolsHelper.Compiler.Compile(preparedExpression); // , // , List <VariableValue> variables = new List <VariableValue>(); // double res = ToolsHelper.Calculator.Calculate(compiledExpression, variables); * This source code was highlighted with Source Code Highlighter .



  6. // PreparedExpression preparedExpression = ToolsHelper.Parser.Parse( "-4+5.5*sin(1/3)*(2+5)" ); CompiledExpression compiledExpression = ToolsHelper.Compiler.Compile(preparedExpression); // , // , List <VariableValue> variables = new List <VariableValue>(); // double res = ToolsHelper.Calculator.Calculate(compiledExpression, variables); * This source code was highlighted with Source Code Highlighter .



  7. // PreparedExpression preparedExpression = ToolsHelper.Parser.Parse( "-4+5.5*sin(1/3)*(2+5)" ); CompiledExpression compiledExpression = ToolsHelper.Compiler.Compile(preparedExpression); // , // , List <VariableValue> variables = new List <VariableValue>(); // double res = ToolsHelper.Calculator.Calculate(compiledExpression, variables); * This source code was highlighted with Source Code Highlighter .



  8. // PreparedExpression preparedExpression = ToolsHelper.Parser.Parse( "-4+5.5*sin(1/3)*(2+5)" ); CompiledExpression compiledExpression = ToolsHelper.Compiler.Compile(preparedExpression); // , // , List <VariableValue> variables = new List <VariableValue>(); // double res = ToolsHelper.Calculator.Calculate(compiledExpression, variables); * This source code was highlighted with Source Code Highlighter .



// PreparedExpression preparedExpression = ToolsHelper.Parser.Parse( "-4+5.5*sin(1/3)*(2+5)" ); CompiledExpression compiledExpression = ToolsHelper.Compiler.Compile(preparedExpression); // , // , List <VariableValue> variables = new List <VariableValue>(); // double res = ToolsHelper.Calculator.Calculate(compiledExpression, variables); * This source code was highlighted with Source Code Highlighter .





2. xml-library configを構成するだけで、必要な機能と演算子をすばやく追加する機能。 いくつかの引数を持つ関数がサポートされています。たとえば、2つのパラメーターを取るmyfunc関数の独自の署名を定義できます。 式では、「myfunc(12、x)」のように呼び出すことができます。 ここで、xは変数であり、計算時にその値を計算機に渡す必要があります。



3つ以上のオペランドを持つ演算子もサポートされます(例として、三項演算子?:ライブラリに既に定義されており、最初のオペランドの符号に応じて、2番目または3番目のオペランドの値を返します。



すべての操作(演算子と関数)は、シグネチャ(ソース文字列内の出現を検索する記号表現)、優先度、オペランドの数、およびこの操作の計算に使用される計算機クラスによって特徴付けられます。 コンピューティングクラスはインターフェイスを実装します





  1. パブリック インターフェイス IOperationCalculator {
  2. /// <summary>
  3. ///呼び出された操作の結果を返します。
  4. /// </ summary>
  5. double Calculate( params double [] parameters);
  6. }
  7. }
*このソースコードは、 ソースコードハイライターで強調表示されました。


したがって、新しい演算子または関数を追加するには、この関数の計算機クラスを定義し、フォームのOperations.xmlにエントリを追加する必要があります





  1. < 操作 = "sinus" オペランド = "1" kind = "関数" >
  2. < 署名 >
  3. < 署名 番号 = "1" = "sin" />
  4. </ 署名 >
  5. < 計算機 タイプ = "ELW.Library.Math.Calculators.Standard.CalculatorSinus、ELW.Library.Math" />
  6. </ 操作 >
*このソースコードは、 ソースコードハイライターで強調表示されました。




初期化時に、ライブラリは追加された関数の処理に必要なタイプをロードし、この操作を選択した計算機クラスのインスタンスにマッピングします。 計算中に、渡されたパラメーターで対応する関数Calculate()が呼び出されます。



3.定数を計算することにより、コンパイルされた式を最適化する機能。 たとえば、式(3 + 5)/ xは8 / xの形式に縮小できます。 結果の式は、元の式の代わりに計算に使用でき、その関数のわずかに簡略化されたバージョンとしてユーザーに表示することもできます。 最適化アルゴリズムは、新しい機能を追加することで改善できます(もちろん、誰かがそのようなアイデアを思いついた場合)。



4.式の変換の中間段階を制御する機能。 文字列から一連のシグネチャとオペランド、そしてオペランドと演算からポーランド表記法を逆に、またはその逆に。 一般に、可能な遷移は次の図に反映されます。

画像

StringとDoubleはプリミティブ型であり、式の処理はそれらで始まり、通常はそれらで終わります。

準備された式-要素のセットで構成され、各要素は定数、変数名、またはブラケットやコンマなどの区切り文字、または操作の文字列署名です。 たとえば、式(a + b)/ 3は、「(」、「a」、「+」、「b」、「)」、「/」、3のセットになります。ここの数字3は文字列形式ではなくなりました、およびDouble。



コンパイルされた式-後置記法でのオペランドとその演算のセット、つまり、電卓が食べるもの。 これは、オペランド(定数または変数名)と操作(演算子または関数)の配列です。 この式を入力として受け取る電卓は、単純なアルゴリズムに従って演算を行い、オペランドと演算に関する情報を交互に抽出し、オペランドスタックで逐次計算を実行します。



5. .NET Framework 3.5および.NET 2.0の両方で構築されます。 自動化のための添付されたnantスクリプト

アセンブリは、Visual Studioと組み合わせて使用​​できます。



ライブラリのサンプルのスクリーンショット:

画像

エピローグ。



これまでの可能性はあまり大きくありませんが、演算子の計算の優先順位を変更したり、数式の基本的な最適化を行ったりして、独自の演算子の発明を試すのに十分です。



ライブラリソースとテストアプリケーションをダウンロードする



反射材料:



en.wikipedia.org/wiki/Background_Polish_Record

msdn.microsoft.com/en-us/library/ms139741.aspx



All Articles