ガクト筆算計算機

※空欄に小数点のある数値を入れて、かけ算か割り算を選んでください。
※数値は半角数字で入れてください。



このページではjavaScriptという言語を使用して計算、筆算の描画を行なっております
掛け算を計算するプログラムは割り算に比べると簡単です。
掛け算をする部分の概要部分はこのような表記になっております。

auto_multiply(){
	this.valCheck();
	if(this.error.length===0){
		this.setCanvas();
		//this.setGrid();
		this.m_putEq();
		this.kakezan();
		this.m_eq();
	}else{
		this.alertError();
	}
}

といっても、何を書いているのかさっぱりわからないのが普通だと思います。
ですが、プログラミング「言語」という以上、日本語に翻訳することが可能です。
上のコードを1行ずつ翻訳してみましょう。

//自動掛け算機能
auto_multiply(){
	//値に問題がないかチェックする
	this.valCheck();
	//問題点が1つもない場合は
	if(this.error.length===0){
		//筆算を描画する領域を用意する
		this.setCanvas();
		//グリッドを表示する
		//this.setGrid();
		//掛け算を描画する
		this.m_putEq();
		//1桁ごとに計算する部分を描画する
		this.kakezan();
		this.m_eq();
	}else{
		//エラーがあればそれを出力する
		this.alertError();
	}
}

重要な部分だけを日本語にしてみました。
ここでコードの中にスラッシュ(/)の記号が目立ちますね。
この記号を二つ重ねたものは、コメントを意味します。
このスラッシュを二つ重ねたものの後に書いてある部分はプログラムの中のメモのようなものであり、プログラムとしては処理されません。
プログラマがどういう意図で書いたかを忘れないように、また、わかりやすく整理するためにコメントを書きます。
ですので、日本語の部分は基本的にはコメントです。

しかし、1行だけ英語のプログラムなのにコメントになっている部分がありますね。

//this.setGrid();
この部分です。
これは、プログラムとして書いたものを一時的にプログラムとして処理させないようにしております。
そう言う意味でコメントではないのですが、コメント化することによって、一部の処理を行わないようにしております。
では、このスラッシュを取り除くとどうなるでしょう?
このようにグリッドが表示されます。
これはプログラムの途中で、文字や小数点の位置を微調整して正確に合わせるために、方眼紙状にマス目を表示していた時のものです。
このマス目を基準に描画することで位置を揃えることができたわけですが、最後には不要になります。
そのため、最後はスラッシュを2つ入れることによって無効化しているわけです。
このように、コメントにすることでプログラムの一部を無効化することを「コメントアウト」と呼びます。

さて、掛け算の根幹部分のプログラムをみてみましょう。

kakezan(){
	this.pointer=this.maxCol-this.m_offset;
	this.pointer_y=3;
	for(var i=1;i <= this.sndStr.length;i++){
		var seki = (this.fstInt*Number(this.sndStr[this.sndStr.length-i]));
		seki=String(seki);
		if(seki!=="0"){
			for(var j=1;j <= seki.length;j++){
				this.putChar(
					seki[seki.length-j],
					this.pointer-j,
					this.pointer_y,
					false,
					false
					)
			}
			this.pointer_y++;
		}
		this.pointer--;
	}
	this.m_putDot();
	this.m_putSeki();
}

割り算の筆算と違い、掛け算はこの部分だけでほとんどの処理ができております。
特に重要なのは

for(var i=1;i <= this.sndStr.length;i++){
この部分です。
forという構文は繰り返しを意味します。
中身は3つの式に分かれており、
for(初期条件;繰り返し条件;増減式)
という意味合いになっております。
ここでは、初期条件が var i = 1です。
これはiという変数の値を1にするという意味です。
次の繰り返し条件に当たるi <= this.sndStr.lengthというのはiが2番目の数(かける数)の文字の長さに達するまで、という意味になります。
3番目のi++というのはiに1を足すという意味です。
これらをまとめると、
「iが1ではじまって、かける数の長さに達するまでiを1ずつ増やしながら計算をくりかえしなさい」
という意味になります。
実際に筆算をするときも、一番小さい位から一番大きい位に達するまで1文字ずつ計算していきますよね。
それをこのプログラムで実現しているわけです。
このように同じ処理の一部を変えながら繰り返していく、という処理はこのようなプログラムだけでなく、企業内で使われているシステムや、ゲームでも基本は同じです。

このページではjavaScriptという言語を使用して計算、筆算の描画を行なっております
割り算を計算するプログラムは非常に複雑です。
割り算をする部分の概要部分はこのような表記になっております。

auto_divide(){
	this.fstShou=undefined;
	this.valCheck();
	if(this.error.length===0){
		this.setCanvas();
		//this.setGrid();
		this.setEq();
		this.warizan();
		this.d_eq();
	}else{
		this.alertError();
	}
}

重要な部分をかいつまんで説明しましょう。 まず3行目の

	this.valCheck();
の部分です。
ここでは入力された値に問題がないかをチェックしております。
これを実行することにより、数字を入力すべきところにアルファベットやひらがなが入力されたりした場合にエラーを取得することができます。
たった1行で?と思うかもしれませんが、この「valCheck();」というものの詳細については別の箇所に記してあります。

valCheck(){
	this.fst = Number($('#first').val());
	this.snd = Number($('#second').val());
	this.fstStr = String(this.fst).replace(".","");
	this.sndStr = String(this.snd).replace(".","");
	this.getNumbers();
	if(this.fst==0 || this.snd==0){
		this.error.push('0以上の値を入れてください');
	}
	if(String(this.snd).match(/^([0-9]\d*|0)(\.\d+)?$/)===null || String(this.fst).match(/^([1-9]\d*|0)(\.\d+)?$/)===null){
		this.error.push('整数、もしくは少数を入れてください');
	}
	if(this.fstStr.length>6 || this.sndStr.length>6){
		this.error.push('上限は6桁です');
	}
}

これがvalCheckの詳細について記された部分です。
このように、概略を最初に書いておいて、その細かな処理は別の場所に書いて、わかりやすくプログラムを整理しているのです。
とはいえ、これだけではどういうことかわかりづらいですよね。
では、最初に紹介した割り算の概要部分を日本語に翻訳してみましょう。

//自動で割り算
auto_divide(){
	//この計算の商をいったん未定義な状態にする
	this.fstShou=undefined;
	//入力された値に問題がないかチェックする
	this.valCheck();
	//もしエラーがなければ割り算を開始する
	if(this.error.length===0){
		//筆算を描画するエリアを用意する
		this.setCanvas();
		//グリッドを表示する
		//this.setGrid();
		//計算式部分を表示する
		this.setEq();
		//人間と同じ手法で割り算の筆算を行う
		this.warizan();
		//割り算の式を表示する
		this.d_eq();
	}else{
		//エラーがあった場合はエラーを表示する
		this.alertError();
	}
}

プログラミング言語というのは、所詮言語です。
言語である以上は日本語に翻訳することができます。
言語である以上、わかりやすく書く必要があります。
もちろん、読み手にわかりやすかろうが、わかりにくかろうが、コンピューターはちゃんと処理してくれます。
ですが、それを修正したりメンテナンスしたりする人にとっては、わかりにくく書いてしまうと大変です。
例えば、次に示す2つの文章を比較してみてください。

入力された値が6桁だったらエラーを出力して、
入力された値に数字以外のものが入ったらエラーを出力して、
入力された値が0だったらエラーを出力して、
エラーが1つもなければ、割り算を開始する。
入力された値をチェックして問題なければ割り算を開始する。
チェックする時には、
値が6桁以下に収まっているか、
値が0でないか、
値に数字以外のものがはいっていないか、
をチェックする。
どうみても後者の方がわかりやすいですよね。

さて、それでも「人間と同じ手法で割り算の筆算を行う」の部分は非常に複雑になります。
その部分のコードの一部をみてみましょう。

putSa(){
	var x = this.sndStr.length + this.pointer;
	this.sa = String(this.currentNumber-Number(this.seki));
	if(this.sa!=='0' || this.pointer <= this.fstStr.length){
		for(var i=this.sa.length-1;i>=0;i--){
			this.putChar(this.sa[i],x,this.pointer_y,false,true);
			x--;
		}
	}

	//一つ上のものをおろしてくる
	if(this.pointer + 1 < this.fstStr.length){
		this.putChar(this.fstStr[this.pointer+1],this.sndStr.length+this.pointer+1,this.pointer_y,false,true);
	}else{
		if(this.amari===0){
		}else{
			this.putChar('0',this.sndStr.length+this.pointer+1,this.pointer_y,false,true);
		}
	}

	//1わる333のような場合
	if(this.pointer-this.pre_pointer>1){
		for(var i=this.pre_pointer;i < this.pointer;i++){
			if(i+1 < this.fstStr.length){
				this.putChar(this.fstStr[i+1],this.sndStr.length+i+1,this.pointer_y-2,false,true);
			}else{
				this.putChar('0',this.sndStr.length+i+1,this.pointer_y-2,false,true);
			}
		}
	}
	

	this.pointer_y++;
	this.currentNumber=this.amari;
	this.pre_pointer=this.pointer;
}

この部分は、割り算の筆算をする上ではごく一部になります。
具体的には下の画像の矢印の部分です。
我々が紙と鉛筆でやっている筆算は、この部分だけでも実際にプログラムに書くとこれだけ複雑になってしまいます。

では、割り算をする時に、毎回こんなに複雑なプログラムを書かなければならないかというと、それは違います。
今回のプログラムでは、あくまで人間と同じように計算することを、プログラムで表現してみました。
答えだけが必要な場合は、

document.write(12.34/34.56);
と1行だけで終わりです。
ただし、小数の計算をする場合は、「少数丸め誤差」という問題が生じ、計算結果が正確にならない場合があります。
そのため、小数の計算を正確にする場合には、専用のライブラリを導入するか、一度整数にして、あとで位を調整する必要があります。
いずれにしても、我々はこれだけ難しい処理を、日常的に行なっているわけです。