ホーム ] アプリ ] コントロール ] クラスライブラリ ]

上へ
実行時間計測ラブラリ
EXIF情報ライブラリ
文字式演算
クイックソートライブラリ
多倍長演算ライブラリ
多倍長演算ライブラリU
画像処理ライブラリ

文字式演算(FreeFormula)

目次

最終更新日:2007/05/19  一部修正

●概要

 文字列で与えられた数式を数値演算し、その値を求める。逆ポーランド形式の式も得られる。

●原理

 通常の数式は、中置法で、3 + 5 などと書く。しかし、この書式はコンピュータにとっては処理が困難となるので、後置法(Postfix form)と呼ばれる方式で表す。3 5 + となる。この方法では、演算子が現れたら、それ以前の変数をそれで演算することになり、機械的に処理できる。

 少し、複雑な例で説明する。

 3 + 5 * 7/(8 - 6)  → 3 5 7 * 8 6 - / +

  1. 逆ポーランド数式を頭から検索し、数値であれば、スタックに積む。3,5,7
  2. 演算子の場合は演算を行う。例では、先ず、* が現れるので、その前の、5 と 7 を乗算する。この時、演算結果と5.7を置き換える。3,(5*7)
  3. 8、6は数値なのでスタックに積むだけ。3,(5*7),8,6
  4. 次に、- があるので、その前の8、6 で演算する。3,(5*7),(8-6)
  5. / があるが、この場合は、,(5*7)、(8-6) で演算する。3,(5*7)/(8-6)
  6. 最後に、+ があるので、3 + (5*7)/(8-6) を演算する。

原理の詳細はTipsの逆ポーランド文字式演算を参照方。

 このライブラリでは、更に複雑な、数学関数(単項、二項)も記述できるようにしている。

●特徴

  • ライブラリは共有型となっている。
  • 初等関数を使った数式を扱える。
  • 変数、定数、数学定数を記述できる。
  • 数値は全てDouble扱い。
  • 一応の文法チェックを行っている。

●技術解説

○処理概要

 例では項が一文字であるが、実際には複数文字の集合が最小単位(これをトークンと言う)になっているので、解析処理はやや複雑になる。概ね、以下の手順となっている。

  1. 与えられた原始数式に不正な文字がないかを調べる。
  2. 数式を最小単位であるトークンに分解する。
  3. トークンに隣接するトークンを調べ、文法チェックを行う。
  4. 二項数学関数f(a,b)であれば、その関数の終端までに、分離符 "," が1個あることを確認する。その他の場合は、不正とする。
  5. トークン群から逆ポーランド形式の数式にする。
  6. 逆ポーランド数式と変数配列(数式に現れた変数の一覧)を返す。
  7. 要求があれば、数式を演算する。

○トークン分解

 トークンは、数値、変数、演算子、括弧、分離符、関数などとなる。以下のように、優先度(Priority)と識別番号(TokenID)を定義しており、構造体Tokenで表し、トークン配列(Tokens())のサイズは1000固定としている。これは、以前は動的配列であったが、頻繁に配列の生成/消滅があり、メモリを浪費するので固定長とした。1000トークンあれば、実用上問題はない。

・Priority:大きい方が優先度高い

9 = (
5 = 変数、定数、常数、数値
4 = 関数
3 = ^
2 = * /
1 = + -
0 = )
-1 = #   #は内部処理用(ストッパー)

・TokenID

0 = 非因子
1 台 = 括弧
10 台 = 演算子
100 台 = 関数(単項)
200 台 = 関数(二項)
500 台 = 変数X、Y
600 台 = 定数A、B、C、D・・・・
700 台 = 数値(文字列)
800 台 = 常数π、e

・文字列のかぶり」処理

 例えば、A、 Abs、あるいは、Sin、 Sinh は、頭がかぶっているので、検索は、文字数の多いものを優先して確認する。

・単項演算子処理

 +式や -式は単項演算子でもあるので、前後関係より以下のような特殊処理が必要となる。

 + が先頭であるか直前のトークンが、"("、"," であれば、これは単項演算子なので、この + は省く。

 - が先頭であるか直前のトークンが、"("、"," であれば、これは単項演算子なので、0 - 式 にする。

○文法チェック

 面倒くさい処理であるが、それなりに実装している。全体的、機械的に行える手法が必要である。以下の方法で行っている。

  1. あるトークンを取りだす。
  2. 先頭にあっても良いかチェック
  3. 最後尾にあって良いかチェック
  4. それが、二項数学関数であれば、関数の終端までをチェックし、(式1, 式2) となっているか確認する。但し、ここでは式1/2の中身まではチェックしない。ここで見つけた正しい "," のTokenID を 9 にして置く(通常は 3)。
  5. それが、単項数学関数であれば、関数の終端までをチェックし、(式) となっているか確認する。但し、ここでは式の中身まではチェックしない。
  6. 次のトークンを調べ、許可された組み合わせかどうかチェックする。
     例えば、+ であれば、次のトークンは、関数、変数、数値、( のみが許されるなど。
  7. 途中、"," で、TokeID が 3 のものが見つかれば、不正な"," となる。
  8. "(" があれば、+1 し、")" があれば、-1 する括弧カウンタを儲け、途中で、カウンタが負になれば、エラーで、最後に、カウンタが 0 でなくてもエラーとする。

○逆ポーランド変換

 文法チェックを経たトークン群は、機械的に逆ポランド変換できる。二つのスタック(サイズ1000、Stack()とPostFix())を準備する。スタックは構造体Tokenの配列である。Stack(0)にスタッパを入れておく。

  1. Tokens()から一つ、トークンを取り出す。
  2. "("ではなく、この優先度が、Stack()トップの優先度と同じか低い間は、PostFix()にStack()からトークンを移動する。但し、","は無視する。
  3. 上記が終われば、")"以外をStack()に積む。
  4. これを繰り返す。
  5. 全トークンの処理が終われば、Stack()に残存するトークンをPostFix()に移動する。

PostFix() の1から逆ポーランド数式のトークンが格納されている。