おもしろいものができた。

昨晩から、BNF記法とか調べながら、数式を処理するプログラムを
書いていたら、おもしろいものができあがった。
変数が使えて、総和とか積分の近似ができたりします。
ソースコードと実行ファイルをおいておくので、
みたい方は見てみてください。

http://yasuharu.net/admin/diary/img/EvalExpression.zip

最初の方は、BNF記法を使って、きっちりと書いていたのですが、
最後のほう、特に、2つ以上の引数を取る関数の引数解析を
かなり強引にやっているので、そこら辺でエラーが出るかもしれません。
構文解析の方法としては、関数の引数を解析する部分以外は、
再帰下降構文解析を用いて、左再帰の部分を右再帰に書き換えて
解析しています。
引数の解析の部分は、自分の頭の中で考えた適当なものなので、
あんまり、信用ができません。

まず、ソフトの使い方。

起動すると、「Please input expression.」と出ているので、
適当な数式を入力してください。
エンターを押すと、計算が行われます。
エラー処理はあんまりやっていないので、突然落ちることが
あるかもしれません。
また、マルチバイト文字とか入れたときは、まだ、
試していませんが、多くの場合、落ちると思います。

使用できる構文の説明。

通常の算術演算の通りにほとんどできるはずです。
例えば、「1 - - 1」とやると、結果として2が表示されます。
ただし、「2sin(x)」といった、「×」の省略はできません。
あと、コンピュータで数式を用いる場合にだけ用いる
記号などは、通常の算術演算と異なります。
演算子に関しては、次のように定義されています。

 + : 加法
 - : 減法
 * : 乗法
 / : 除法
 ^ : 累乗
 () :括弧

実装されている関数と定数の説明。

いくつかの関数と定数ははじめから実装されています。
以下はそのリストです。

 sin(x) : 三角関数のsin。xは弧度法。
 cos(x) : 三角関数のcos。xは弧度法。
 tan(x) : 三角関数のtan。xは弧度法。
 log(x) : eを底とする対数。
 log10(x) : 10を底とする対数。
 abs(x) : 絶対値。
 sqrt(x) : 平方根。
 rad2deg(x) : 弧度法から度数法へ変換。
 deg2rad(x) : 度数法から弧度法へ変換。

(以下の関数に関して、引数名の前に「*」がついているものは
その引数が数式として解釈されます。)

 integral(x1,x2,x3,x4,x5) : 積分を行う。
  x1 : 被積分変数
  x2 : 積分区間の下限
  
x3 : 積分区間の上限
  x4 : 精度
  *x5 : 積分を行う関数

 set(x1,x2) : 変数をセットする。
  x1 : 変数名
  *x2 : 値

 sigma(x) : 総和を求める。
  x1 : 対象の変数
  x2 : 開始値
  
x3 : 終了値
  *x4 : 式

変数の取り扱いに関する説明。
コンソール上から入力された変数は、そのソフトを終了するまで保持されます。
変数の保持に関しては、コンソールから入力された変数は、再度set関数を
使うことで再代入できますが、そうではない、関数の引数の中で定義されたものは
コンソール上から入力されたもののコピーが渡されているだけです。
従って、

set(x,1)
sigma(y,0,10,set(x,x+1))

と、入力した場合、表示される値は、22です。
set(x,1)でxに1が代入され、それより深いネストの部分では、xのコピーのみしか
渡されていないため、元々のxには影響を与えません。

例。
このソフトを使った例をいくつかあげます。
例えば、x^2に関して[0,1]の積分値を近似するとします。
まず、integral関数を使った例。

integral(x,0,1,10,x^2)
Result is 0.285

integral(x,0,1,100,x^2)
Result is 0.32835

integral(x,0,1,1000,x^2)
Result is 0.332834

integral(x,0,1,2000,x^2)
Result is 0.333083

精度を上げることで、答えの値(0.333...)に近づいていきます。
ただし、精度を上げることで、処理時間が長くなります。
また、複数CPUには対応していないので、仮に、Core2 Duoのマシンなどで
動かしたとしても、半分の演算しか行いません。

これをsigma関数を使って書き換えると次のようになります。

sigma(x,0,1000,(0 + (1 - 0) / 1000 * x)^2 * (1 - 0) / 1000)

また、変数の機能を使うことで、次のようにもできます。

set(d,1000)
set(a,0)
set(b,1)
sigma(x,0,d,(a + (b - a) / d * x)^2 * (b - a) / d)

これらの構文は、再帰させることが可能です。
例えば、球の体積を求めるとすると、

8 * integral(x,0,1,100,integral(y,0,sqrt(1 - x^2),100,sqrt(1 - x^2 - y^2)))

と計算することができます。
この結果は、

8 * integral(x,0,1,100,integral(y,0,sqrt(1 - x^2),100,sqrt(1 - x^2 - y^2)))
Result is 4.24539
8 * integral(x,0,1,200,integral(y,0,sqrt(1 - x^2),200,sqrt(1 - x^2 - y^2)))
Result is 4.2173

4 / 3 * pi * 1^2
Result is 4.18879

となり、あまり精度はよくありませんが、計算することができます。

Posted at : 2008-03-20 17:47:20 / Category : none

Comments

はじめてコメントさせて頂きます。数式を処理するプログラムを探していたら、こちらにたどり着きました。関数が使えて、しかも途中で変数に値をセットすることもできるとのこと。ソースを見せて頂こうとリンクをクリックしましたがリンクが切れているようです。少し前の記事ですがリンクの修正いただけると幸いです。

林 - 2020-05-26 08:57:03

ご指摘ありがとうございます。
修正しましたので、ぜひご参考にいただければと思います。

yasuharu - 2020-05-26 09:56:51

リンク先を修正頂きましてありがとうございます。早速実行してみましたところ期待以上でした。後ほど実行しながら、ソースを見て勉強したいと思います。本当にありがとうございました。

林 - 2020-05-26 17:13:28

Send comment


Name


Mail-address (empty is OK. If you want to notify update, please fill mail-address.)


Bot check code (240329 と入力してください / Please input 240329.)