[Labyrinthe Noir]>[Top]>[こども工作教室]>

電卓のソースと解説

HTMLファイルの作成

電卓用に「calc.html」を作成して、保存します。

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>電卓</title> </head> <body> <h3>電卓</h3> <hr>
</body> </html>

電卓用のテーブルを作成

基盤となるテーブルを作成します。

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>電卓</title>
</head>
<body>
<h3>電卓</h3>
<hr>
<form name="calc">
<table border="2">
<tr>
<td></td><td></td><td></td><td></td>
</tr>
<tr>
<td></td><td></td><td></td><td></td>
</tr>
<tr>
<td></td><td></td><td></td><td></td>
</tr>
<tr>
<td></td><td></td><td></td><td></td>
</tr>
</table>
</form>

</body>
</html>

電卓用のキーをボタンで並べますので、<table></table>の前後に<form>タグを付けて囲みます。
フォームには「calc」という名前を付けておきましょう。
テーブルは4×4のマス目になっています。

ボタンを配置する

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>電卓</title>
</head>
<body>
<h3>電卓</h3>
<hr>
<form name="calc">
<table border="2">
<tr>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
</tr>
<tr>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
</tr>
<tr>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
</tr>
<tr>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
</tr>
</table>
</form>
</body>
</html>

次にボタンを全ての枠に入れておきます。
ボタンを押すと計算を実行するので、「onClick」からユーザー関数calc_run()を呼び出すこととします。

1つ作って、あとはコピーすれば楽ですね。

コピーは「Ctrl」+「C」、貼り付けは「Ctrl」+「V」です。

ボタンに文字を入れる

ボタンに数字や計算の記号を書きます。
文字の大きさでボタンの大きさが決まるので、押しやすい大きさにするため全角(日本語入力)で文字を入れます。

<form name="calc">
<table border="2">
<tr>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="÷" onClick="calc_run()"></td>
</tr>
<tr>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="×" onClick="calc_run()"></td>
</tr>
<tr>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
</tr>
<tr>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
<td><input type="button" value="" onClick="calc_run()"></td>
</tr>
</table>
</form>

「÷」は「わる」、「×」は「ばつ」で変換できます。
「・」は小数点(.)のことですが、ボタンにしたときに見やすくするため中点を使用しています。

計算結果の表示

次に計算結果を表示する部分を作りましょう。

<form name="calc">
<table border="2">
<tr>
<th colspan="3" align="right"><div id="output">0</div></th>
<th><div id="type"></div></th>
</tr>
<tr>
<td><input type="button" value="7" onClick="calc_run()"></td>
<td><input type="button" value="8" onClick="calc_run()"></td>
<td><input type="button" value="9" onClick="calc_run()"></td>
<td><input type="button" value="÷" onClick="calc_run()"></td>
</tr>

ボタンの上に1行付け足して、表示用の<div>タグを2つ取り付けます。

1つ目は計算結果の数字を表示する部分です。
数字は右寄せにしたいので、<td>タグ内に「align="right"」を使っています。
<div>タグ内には最初に「0」を表示させています。

2つ目は、計算の種類(記号)を表示するのに使います。数字の入力が終わったときにどんな計算が行われるか表示しています。
電卓は「5」「+」「2」「-」とボタンを押すと「-」を押したときに「5+2」を実行します。そのため、数字の前に押された記号を表示して残しておきます。

電卓の特徴を考える

スクリプトを書く前に、電卓の特徴を考えてみましょう。

使い方の基本は、数字→記号→数字→記号と、数字と記号の入力が交互に行われます。
数字は1つではなく複数のキーを連続で押し、記号が入力されると1つの数字として確定します。また、数字の間には小数点「.」が入ることもあります。

記号が押されると、計算が実行されます。しかし、計算はそのとき押された記号ではなく、その前に押された記号が使われます。
そのため、「1つ前の計算結果」「1つ前の計算記号」「直前に入力された複数の数字」「次の計算のための記号」の4つの要素が揃ったときに計算が実行されることになります。
また、記号のキーが連続して押された場合は、最後に押した計算記号が記録されます。

「=」を押すと計算が実行されますが、これに続いて数字が押されると、計算結果をクリアしなければならない。
途中で計算をクリアするボタンがないので、「=」を2度連続で押すと、クリアする機能を付けたいと思います。

スクリプトの初期設定

それではスクリプトを書いていきましょう。
使用する変数を予想して初期設定として作っておきます。

<script language="javascript">
ans = 0;
num = "0";
key = "";
kigou = "";
   
function calc_run() {

}
</script>

まず、計算中の数字を入れるために変数ansを用意します。
押された数字のキーを順番に記録する必要があるので、変数numを使います。この変数numには「0.」という状態も考えられますし、数値としてではなく文字列として数字をつなげるので、文字列として扱う必要があります。「0」を「""」で囲っているのはそういう理由からです。
そして、1つ前に押されたキーを記録するために変数keyを使います。直前に押されたキーと比較して、処理を切り換えます。
数字がいくつか押された後に計算をさせるため、その前に押された記号キーを覚えておくために変数kigouを用意します。

ボタンからのイベントを受けるためにユーザー関数calc_run()も必要です。

キーからデータを送る

数字のキーを押すと数字を送り、記号のキーを押すと文字を送ります。

<tr>
<td><input type="button" value="7" onClick="calc_run(7)"></td>
<td><input type="button" value="8" onClick="calc_run(8)"></td>
<td><input type="button" value="9" onClick="calc_run(9)"></td>
<td><input type="button" value="÷" onClick="calc_run('/')"></td>
</tr>
<tr>
<td><input type="button" value="4" onClick="calc_run(4)"></td>
<td><input type="button" value="5" onClick="calc_run(5)"></td>
<td><input type="button" value="6" onClick="calc_run(6)"></td>
<td><input type="button" value="×" onClick="calc_run('*')"></td>
</tr>
<tr>
<td><input type="button" value="1" onClick="calc_run(1)"></td>
<td><input type="button" value="2" onClick="calc_run(2)"></td>
<td><input type="button" value="3" onClick="calc_run(3)"></td>
<td><input type="button" value="-" onClick="calc_run('-')"></td>
</tr>
<tr>
<td><input type="button" value="0" onClick="calc_run(0)"></td>
<td><input type="button" value="・" onClick="calc_run('.')"></td>
<td><input type="button" value="=" onClick="calc_run('=')"></td>
<td><input type="button" value="+" onClick="calc_run('+')"></td>
</tr>

数字はそのままの数値を記入します。記号の場合は文字列なので「''」の中に書きます。

JavaScriptは同じ変数で数値も文字列も受け入れる柔軟な特徴があります。他の言語だと別々の変数を用意しなければいけません。

キーからデータを受け取る

キーが押されたときに実行されるユーザー関数calc_run()のスクリプトを書きましょう。

function calc_run(btn) {
	if (!isNaN(btn)) {
		if (!isNaN(key)) { 

		}
	} else {
		if (!isNaN(key)) {

		} 
		kigou = btn;
	}
	key = btn;
}

キーから送られたデータは一旦変数btnで受け取ります。

まず、今押されたキーが入った変数btnの中身が数値か文字かで分岐しています。
「isNaN()」は対象が数値ではない(NaN)ことを調べる関数です。
「isNaN(btn)」とすると、変数btnが文字列ならtrueを、数値ならfalseを返します。「!」を付けて結果を逆にしているので、if文の結果は変数btnが数値なら真(true)となります。

更に、1回目の分岐のそれぞれの中にif文を使って、前に押されたキーが入っている変数keyを調べます。

記号を受け取った場合、その最後に変数btnから変数kigouに受け取ったデータを移し替えています。

そして、全体の最後には、変数btnを変数keyに入れて、後で直前のキー入力が何かを参照できるようにしています。

前のキーを調べて分岐、次に今のキーを調べて処理を分岐させるという大まかな流れを作っておきます。

押したキーを画面に表示(1)

計算は後回しにして、押されたキーを表示する部分を作りましょう。

function calc_run(btn) {
	if (!isNaN(btn)) {
		if (!isNaN(key)) {
			num += ""+btn;
		} else {
			num = ""+btn;
		}
		document.getElementById("output").innerHTML = num;
	} else {
		if (!isNaN(key)) {

		}
		kigou = btn;
	}
	key = btn;
}

まずは押されたキーが数字のときの処理です。「if (!isNaN(btn))」が真の場合になります。

次のif文で前のキーを判別して処理がまた2つに分かれます。

「if (!isNaN(key))」が真の場合とは、数字が押されているので、連続して数字が押されたという状況です。
ここでは「num += ""+btn」となっています。
「num += btn」としてしまうと、変数btnに数値が入っているため足し算になってしまい、これでは意味がありません。
数字のキーがが連続で入力されると、それらをつないで数字にしなければいけないので、文字列として押されたキーを順番に繋がなければダメなのです。
そこで、「""」を挟むことで文字列を変数numに足すという動作にしています。

次に、「if (!isNaN(key))」が偽の場合で、記号の後に数値が押されたという状況です。
この場合は変数numに文字列化した変数btnを入れるだけなので、「""」を挟んで数値を文字列として代入しています。

2つ目の分岐が終了したところで、今入力されたキーを反映させた変数numを表示します。

押したキーを画面に表示(2)

次は押したキーが記号のときの処理です。最初のif文で「if (!isNaN(btn))」が偽だった場合です。

function calc_run(btn) {
	if (!isNaN(btn)) {
		if (!isNaN(key)) {
			num += ""+btn;
		} else {
			num = ""+btn;
		}
		document.getElementById("output").innerHTML = num;
	} else {
		if (!isNaN(key)) {

		}
		kigou = btn;
		document.getElementById("type").innerHTML = kigou;
	}
	key = btn;
}

記号が押されたときは、変数kigouに記録が残されますので、そのまま変数kigou内の文字を画面に表示しています。
前のキーに関係なく、最後に押された記号を表示するだけです。

本来ならば記号が連続した場合は、記号を入れ換えるだけで終わりですが、数字の後に記号が押されたときは、計算結果も出さなくてはいけません。
計算実行のプログラムはもう少し後で作ります。

問題点:最初の「0」が残る

変数numが文字列になっているので、「0」が入っているときに数字を押すと、「01」のように余計な「0」が数字に付いてしまいます。

function calc_run(btn) {
	if (!isNaN(btn)) {
		if (!isNaN(key)) {
			if (num == "0") {
				num = ""+btn;
			} else {
				num += ""+btn;
			}
		} else {
			num = ""+btn;
		}
		document.getElementById("output").innerHTML = num;
	} else {
		if (!isNaN(key)) {

		}
		kigou = btn;
		document.getElementById("type").innerHTML = kigou;
	}
	key = btn;
}

記号の後ならば、代入されるのでそれまでの変数numは消えてしまいますので、数字が連続したときの処理を、if文を使って2つに分けます。

「0」が入っているときは、入力された数字を文字列化して代入します。

「0」以外の文字列が入っているときは、その前に数字が入力されているので、後ろに文字として数字を付け足します。

「0」以外の文字列には「10」のように「0」が含まれていたり、直前に「0」が入力された場合もあります。
「0」があるかどうかという判断をするのではなく、「0」そのものかどうかという判断が必要なのです。

【この時点の calc.html を別枠で表示】

特殊なキー操作を作る:「・」

電卓のボタンを押すと、1つだけ期待通りに動かないボタンがあります。 「・」(小数点)です。
これは記号でありながら数字の一部なので、変数numに入るように処理が必要です。

<tr>
<td><input type="button" value="0" onClick="calc_run(0)"></td>
<td><input type="button" value="・" onClick="calc_period()"></td>
<td><input type="button" value="=" onClick="calc_run('=')"></td>
<td><input type="button" value="+" onClick="calc_run('+')"></td>
</tr>

(省略)

function calc_period() { 
	num += "."; 
	document.getElementById("output").innerHTML = num;
}

「・」を記号の処理とは分けるため、専用のユーザー関数calc_period()を使って処理することにしましょう。

ユーザー関数calc_period()では、変数numの後ろに「.」を付けて表示しています。

問題点:2回目の「.」をどうするか

「・」の問題点はこれだけではありません。2回以上押したときにまた「.」が追加されてしまったのでは、数字ではなくなります。

function calc_period() { 
	if (num.indexOf(".") < 0) num += "."; 
	document.getElementById("output").innerHTML = num;
}

if文を追加して、変数numに「・」が含まれていないときだけ処理を行います。

変数numに対し「indexOf()」を使って「・」が含まれているかどうか調べます。この関数は、指定の文字が含まれている場合にその位置を数値で返しますので、見つからなければ「-1」が返ってきます。
なので0より小さいときに「・」の追加を行うようにします。

関数indexOf()は、先頭から指定の文字を検索し、先頭を0番目として値を返します。

特殊なキー操作を作る:「=」

「=」の役割は、それまで貯めた数字を使って計算結果を表示するということです。これは他の記号も同じです。
しかし、2回続けて「=」を押すと、計算を初期化するという特殊な機能を付け加えます。

<tr>
<td><input type="button" value="0" onClick="calc_run(0)"></td>
<td><input type="button" value="・" onClick="calc_period()"></td>
<td><input type="button" value="=" onClick="calc_equal()"></td>
<td><input type="button" value="+" onClick="calc_run('+')"></td>
</tr>

(省略)

function calc_equal() {
	if (key == "=") {
		ans = 0;
		key = "";
	} else {
		ans = eval(ans + kigou + num);
		key = "=";
	}
	num = "0";
	kigou = key;
	document.getElementById("output").innerHTML = ans;
	document.getElementById("type").innerHTML = key;
}

まず、if文で前のキーを調べて「=」なら連続と判断して、変数ansと変数keyを初期化しています。
そうでない場合は、これまで貯めた数字と前の記号を使って計算を実行し、変数ansに入れます。変数keyには「=」を入れおきます。
初期設定にはあと2つの変数があり、これらはif文の後で初期化しています。変数numは計算表示を「0」にするために使っています。変数kigouも記号表示に使っていますが、こちらは変数keyに連動しています。

変数の設定が終わったら、表示部に変数ansと変数keyを表示しています。これまでは表示には変数numと変数kigouを使っていましたが、ここでは違っています。
初期化が行われたときは、どちらを表示しても同じ結果になります。
しかし、通常の「=」の役割として演算が実行されると変数の役割が入れ替わるのです。

演算には関数「eval()」が使われています。これは文字列を計算式として実行するという関数です。
具体的に変数の内容と表示を考えて見ましょう。

演算の仕組み

「5」「+」「3」「=」と押されたときの変数の変化を追いかけましょう。まだ「+」のときは作っていませんが、eval()を同じように使います。
実際には、最初に変数を用意する段階で、およそこの流れを考えておく必要があります。

押されたボタン 変数
key
変数
num
変数
kigou
eval() 変数
ans
数字
表示
記号
表示
(初期状態) "" "0" ""   0 0  
5 "5" ""   0 5  
"+" "0" "+" "05" 5 5 +
3 "3" "+"   5 3 +
"=" "0" "=" "5+3" 8 8 =

数字が押されたときは、変数numを数字表示に、記号が押されたときは演算結果である変数ansを数字表示に出力しています。
記号が押されると、変数numは「0」にして、次の数字が入ってくるために準備します。変数ansには計算結果が入っているので、これを表示するのです。

計算部分を作る

計算結果の表示は、「=」を入力した時だけでなく、四則演算の記号である「+」「-」「×」「÷」のどれかが入力されたときにも実行しなければなりません。

function calc_run(btn) {
	if (!isNaN(btn)) {
		if (!isNaN(key)) {
			if (num == "0") {
				num = ""+btn;
			} else {
				num += ""+btn;
			}
		} else {
			num = ""+btn;
		}
		document.getElementById("output").innerHTML = num;
	} else {
		if (!isNaN(key)) {
			ans = eval(ans + kigou + num);
			num = "0";
			document.getElementById("output").innerHTML = ans;
		}
		kigou = btn;
		document.getElementById("type").innerHTML = kigou;
	}
	key = btn;
}

ここでは、前の入力が数字の場合だけ考えます。
記号が続けて押された場合は、記号を入れ換えるだけなので、「kigou = btn」と「key = btn」が後で実行されるので、他になにもすることはないのです。

それでは、if文の中を見て見ましょう。
計算の実行は、「=」を押したときにすでに作ってあるので、これをそのまま利用します。

計算結果が出たら、変数numは「0」にします。次に数字が入力されたら、また記録をしなくてはならないからです。

表示には変数ansを使います。次の数字が入力されるまでは、計算結果を表示しなければならないためです。

【この時点の calc.html を別枠で表示】

上記calc.htmlには、変数をtitleに表示するデバッグ用のプログラムが入っています。
ブラウザのタイトル表示にユーザー関数実行前の変数key(前キー)、変数btn(押されたキー)、変数ans(計算結果)、変数kigou(記号)、変数num(入力中の数字)が表示されます。

問題点:続けて計算ができない

動作テストをするといくつかの問題点が見つかります。
四則演算を続けて計算することはできるのですが、一度「=」を押すと、次の計算ができなくなるのです。

function calc_run(btn) {
	if (!isNaN(btn)) {
		if (kigou == "=") {
			ans = 0;
			kigou = "";
		}
		if (!isNaN(key)) {
			if (num == "0") {
				num = ""+btn;
			} else {
				num += ""+btn;
			}
		} else {
			num = ""+btn;
		}
		document.getElementById("output").innerHTML = num;
	} else {
		if (!isNaN(key)) {
			ans = eval(ans + kigou + num);
			num = "0";
			document.getElementById("output").innerHTML = ans;
		}
		kigou = btn;
	}
	document.getElementById("type").innerHTML = kigou;
	key = btn;
}

ブラウザのエラーメッセージを調べると、エラーは「ans = eval(ans + kigou + num);」のところで発生しています。
このときの各変数の状況を先ほどの表の続きで見てみよう。

押されたボタン 変数
key
変数
num
変数
kigou
eval() 変数
ans
数字
表示
記号
表示
"=" "0" "=" "5+3" 8 8 =
7 "7" "="   8 7 =
"+" "0" "+" "8=7"      

赤いマスがエラーの発生場所です。確かにブラウザの言うとおりです。

「8=7」は計算式ではありません。それを無理矢理計算させようとしたためにエラーが起きてしまったのです。

そこで、「=」の次に数字が入力されたら、変数ansと変数kigouを初期化することにします。

calc_equal()の最後に計算結果を表示したあとに初期化しておくという方法も考えられます。
しかし、この方法だと、「=」のあとに演算記号が押されても、前の結果を引き継いだ計算ができなくなってしまいます。

calc_run()の数字が入力された場合の直後に、「kigou == "="」の場合に初期化を実行します。

これだけだと、画面に表示された「=」が記号表示に残ってしまいます。
記号が入力されたときにだけ記号の表示をすることになっていましたが、if文の外に出力の命令を移動しておきます。

問題点:小数点の不具合(1)

次に小数点を使った場合の2つの問題点があります。

function calc_period() { 
	if (num.indexOf(".") < 0) num += "."; 
	key = 0;
	document.getElementById("output").innerHTML = num;
}

まずは、簡単な表示の不具合を直しておきます。
この電卓では画面に「0」があるとき、「0.2」と入力する場合、最初の「0」を押さずに「・」を入力すれば「0.」となります。
しかし、次に数字を入力すると「0.」が消えてしまいます。
この現象は、記号を入力した後に発生しますが、エラーの表示はありません。

押されたボタン 変数
key
変数
num
変数
kigou
eval() 変数
ans
数字
表示
記号
表示
(初期状態) "" "0" ""   0 0  
5 "5" ""   0 5  
"+" "0" "+" "05" 5 5 +
"." "0." "+"   5 0. +
3 "3" "+"   5 3 +
"=" "0" "=" "5+3" 8 8 =

「3」を押した時点で表示が「0.3」ではなく「3」になってしまいます。「=」を押してみると、答えが「8」になります。

これは、「・」が数字として扱われていないために起きています。
「3」を押したときに「0.3」とならないのは、数字が連続入力したときの流れに処理が入ってないということです。
記号の次に数字が入力されたことになっているため、「num = ""+btn;」が実行されてしまったのです。

そこで、calc_period()の中で、「・」を数字と見なすために、「key = 0」にしてしまいます。

問題点:小数点の不具合(2)

次にはっきりとエラーが表示される問題を解決しましょう。

function calc_run(btn) {
	if (!isNaN(btn)) { 
		if (kigou == "=") {
			ans = 0;
			kigou = "";
		}
		if (!isNaN(key)) { 
			if (num == "0") {
				num = ""+btn;
			} else {
				num += ""+btn;
			}
		} else {
			num = ""+btn;
		}
		document.getElementById("output").innerHTML = num;
	} else {
		if (!isNaN(key)) {
			if (kigou == "") ans = num;
			else ans = eval(ans + kigou + num);
			num = "0";
			document.getElementById("output").innerHTML = ans;
		}
		kigou = btn;
	}
	document.getElementById("type").innerHTML = kigou;
	key = btn;
}

この不具合もまた「ans = eval(ans + kigou + num);」のところで発生しています。
今度は、「=」の後で、小数点を入力した後に記号を押すと発生します。

押されたボタン 変数
key
変数
num
変数
kigou
eval() 変数
ans
数字
表示
記号
表示
"=" "0" "=" "5+3" 8 8 =
"0" "0." "="   0 0.  
7 "0.7" ""   0 0.7  
"+" "0" "+" "00.7"      

これは、初めて記号を押したときにeval()が実行されることに問題があったのです。
最初の表でも「5」「+」と押したときに「0」「""」「5」が計算に使われて「eval(05)」という計算が行われていました。これはたまたまうまく行ったのです。
今度は「0」「""」「0.7」だったので「eval(00.7)」となり、頭の「0」が計算上問題になったということです。

そこで、calc_run()の記号が入力されたときにif文を使って、記号がないときは計算をしないで、「ans = num」と変数の入替だけ行います。
計算記号があるときは、今まで通り計算を実行します。

今回は{}を省略した形のif~else文になっています。
{}を使うと下のようになります。

if (kigou =="") {
	ans = num;
} else {
	ans = eval(ans + kigou + num);
} 

次のようにも書けます。

if (kigou =="") {ans = num;}
else {ans = eval(ans + kigou + num);} 

elseを改行せずにif文を最後まで1行で書くこともできます。

問題点:小数点の不具合(3)

演算をしている箇所はcalc_equal()の中にもあります。
一見、こちらは問題なさそうですが、小数点の入力の後、他の記号を使わずに「=」を押したときに、はやり同じエラーが発生してしまいます。こちらも修正しておきましょう。

function calc_equal() {
	document.title = key + "=" + ":" + ans + "[" + kigou + "]" + num;
	if (key == "=") {
		ans = 0;
		key = "";
	} else {
		if (kigou == "") ans = num;
		else ans = eval(ans + kigou + num);
		key = "=";
	}
	num = "0";
	kigou = key;
	document.getElementById("output").innerHTML = ans;
	document.getElementById("type").innerHTML = key;
}

これで完成です。

【この時点の calc.html を別枠で表示】

問題点:ブラウザの計算能力の欠陥

実は、小数点の問題はこれで全て解決した訳ではありません。どうしても解決できない致命的な欠陥がブラウザの中にあるのです。
小数点を使う計算をすると計算誤差が発生する場合があり、単純な計算ミスなって現れます。

これはそもそものコンピュータの仕組みそのものが原因です。
コンピュータは、電気で動いています。計算をしたり、結果を表示したり、入力したキーを受け取ったり、全てを電気信号で行っています。
この信号は電流のオンとオフや強弱によって「0」と「1」の状態を表して、すべてを表現しています。
これが2進数と呼ばれるものの原点で、コンピュータは今でも2進数で書かれたマシン語と言われるプログラムを使って動作しています。
いま、「JavaScript」を使ってプログラムを書いていましたが、実はすべてのコンピュータはマシン語以外の言語では動作しないのです。間に翻訳者が居て、必ずマシン語になったプログラムを実行します。
人間が扱う数字は10進数です。他に8進数や16進数というものがありますが、どちらも2進数を単純に書き換えただけのものです。

最大の問題点は2進数に小数がないということなのです。小数を計算するときは、一旦整数にして計算をし、後でもう一度小数に戻すということをします。そのため、限られた桁数で計算をするために数字の小さな部分が消えてしまうのです。

計算表の専用ソフトですら、当初は2進数で計算をしていたため誤差が発生していました。10年ほど経ってようやく10進数計算ができるように改良されたくらいです。
しかし、ほとんどのブラウザでは未だにこの問題が解決していません。小数の引き算や割り算をすると、簡単に誤差が発生します。
例えば 「0.9-0.8」という簡単な式でさえ、「0.1」にならないのです。

10進数計算ができないブラウザで、この電卓を使って「0.9-0.8」を計算すると、「0.09999999999999998」となります。

もちろん、今後はブラウザでも10進数計算ができるようになると思われます。
下記では、スクリプトの実行結果を表示しています。色々なブラウザで結果を見てみると良いでしょう。

このブラウザでは「0.9-0.8」は「」となります。

今後の改良点

・「BS」ボタンを付ける。
・計算履歴の表示。
ボタンのない式入力のできる計算機(実はこれの方が簡単にできる。ヒント:eval())

戻る