前回は時間電卓なる奇妙なものを作成しましたが、今回は普通の電卓をつくります。

前回作成した時間電卓

C#なら簡単 DateTime構造体とTimeSpan構造体を使って時間計算機をつくる

C#なら簡単 TimeSpan構造体を使って時間電卓をつくる

普通の電卓では正しい計算ができない

多くの電卓で「1 + 2 × 3」を計算すると「9」と表示されます。しかし足し算とかけ算が混合した計算の場合、かけ算が先なので正解は 「7」です。ではこのような計算をするにはどうすればよいでしょうか?

試しにWindowsに搭載されている電卓で計算すると「標準電卓」では「9」と表示されますが、「関数電卓」を使うと正しく「7」と表示されます。だから今からやろうとしているのは車輪の再発明です。それでもつきあってくれる方は以下の記事を読んでください。

文字列の数式を計算する方法

文字列の計算式を前から順番にではなく適切な順番で計算する方法としては以下のようなコードであれば正しい計算結果が格納されるのでこれを利用します。

CSharpCodeProviderを使うのは非推奨

CSharpCodeProviderを使って、計算式が含まれるコードの文字列をコンパイルし実行すれば正しい計算結果が取得できます。

ただこの方法はおすすめできません。計算式が変わるたびにその都度コンパイルが必要になります。そうなればメモリに毎回アセンブリが読み込まれるので、その解放について気を遣わなければならなくなり、下手をするといつかOutOfMemoryになる危険性が大きいです。実用的かといわれると大いに疑問です。

DataTableを使う方法

DataTableを使う方法は有力です。DataTableに数式をいれて計算させてその結果を取得するという方法です。

ただし、DataTable.Compute(“計算式”, “”)が返す値をそのまま利用しようとしてもうまくいきません。まず文字列に変換してdouble.Parseメソッドでdouble型に変換された値を取得します。

実行結果
1 + 2 * 3 = 7
(1 + 2) * 3 = 9

巨大な数を計算する

これで一見問題なさそうなのですが、巨大な数を計算しようとするとエラーがでます。

発生した例外

このような例外が発生するのは”500000 * 100000000000000 / 7″がInt64型の範囲を超えてしまっているからです。Calculateメソッドが返す値の型はdouble型ですが、演算はInt64型同士なのでInt64型の範囲を超えてしまうとそれまでです。

そこで計算式の最初に「1.0 × 」をつけます。これだと最初からdouble型で計算がおこなわれるので例外は発生しません。

大きな数の場合、指数表示になってしまいますが、計算結果は取得できます。

実行結果
500000 * 100000000000000 / 7 = 7.142857142857143E+18

文字列の数式を計算するWebアプリをJavaScriptでつくる

文字列の数式を計算するWebアプリをJavaScriptでつくります。サーバーサイドにおける処理はなく、全部クライアントサイドでおこないます。

まず0~9と四則演算にもちいる記号と()が書かれたボタンを用意します。そしてボタンがクリックされたら計算式を表示します。=のボタンが押されたら計算してその結果を返します。また入力をミスしたときのひとつ前にもどって修正できるように←ボタンをつけました。

HTML部分

HTMLソースを示します。

JavaScript部分

数字、小数点、演算子が書かれたボタンをクリックするとbuttonClick関数が呼び出され、数式が生成されていきます。また入力された数式はリアルタイムで表示されます。

app.js

←と書かれているボタンをクリックされたら計算式のうち一番右にある文字を消去します。

ACと書かれたボタンがクリックされたらこれまでに入力された数式と表示されている計算結果をクリアします。

=と書かれているボタンがクリックされたら表示されている計算式を実際に計算できるように置き換えます。全角文字の+-×÷を+-*/に置き換えます。そしてFunction(‘return (‘+calc_string+’);’)()を実行すると計算結果が取得できるので、これを表示します。

もし変数 formula に計算式として正しくない文字列が格納されている場合は例外が発生します。このときは数式が不正である旨を表示します。