2014年4月6日日曜日

人で無しのための計算機理論入門 その10 プログラムの基礎 その4 地味だけ ど大事な論理式


さて、とうとう10回目になったこの「 人で無しのための計算機理論入門」。一応、情報機器を使用したり、それ以上にプログラムさえ書いたりして使いこなしたりする上で、基本的な事項をきちんと押さえておくことがいかに大事かということをお伝えできたと思います。ほら、基本理論て意外に大切でしょう?ということです。
 
これ以上のことを説明し出すと、非常に専門的になりすぎて、普通の人が知っておけば便利だな、という内容から少し遠ざかってしまうことになりそうですので、一旦ここで、この「計算機理論入門」は区切りをつけさせていただきたいと思います。これまで読んでいただき本当にありがとうございました。
 
さて、その記念すべき最終回は、やはり地味に基本を押さえていきたいと思います。
 
以前、二進数とブール代数(論理式)について、「P=NP?問題の覚え書き」というブログの「 充足問題について その前に」という記事で、割合詳しく述べさせていただきました。
 
ここでは、分岐に欠かせない、論理式について、もう一度復習をしておきたいと思います。
 
ところで、「その7」でCPUは、

 0(ゼロ)フラグ:計算の結果が0の時に1、そうでないときは0
 マイナスフラグ: 計算の結果が負の時に1、そうでないときは0
 
というフラグを立てる、というお話をしました。
 
こういう風にフラグというもので計算結果を出したあと分岐をするということは何となくおわかりでしょうが、複数の条件が重なった場合の分岐はどうするか、ここで、論理式というものが必要になります。
 
たとえば、「もし、毎年4月はじめの日曜日 晴れだったら花見実行のメールをメンバーに出す だけど 雨が降ったら中止」というプログラムを書きたいとします。
 
いくつかの表し方があるとは思いますが、たとえば、
 
 ・Dを日付型の変数と定義
 ・Dに今日の日付を記憶
 ・Dが
   4月であるか?
    かつ
   最初の日曜であるか?
  をそれぞれ調べるサブルーチンを呼び出し、
  条件を満たせば、次へ進む。
  そうでなければ終了
 ・天気は晴れ? =>花見メール
  天気は雨?  =>中止メール
 
というように要素を分解して表せば計算機のプログラム的になるのは分かりますよね。(その他の天候の時は空気を読めということです。空気読むのは日本人として大事ですよ、ほんとうに。それができないから(ry)
 
ところで、上の例で条件による分岐のところで”かつ”という言葉が出てきました。少し抽象して
 
 条件Aを満たす
 かつ  
 条件Bを満たす
 
というのは条件Aと条件Bが両方満たされて初めて次に進めるわけですから、ある条件を満たしたとき立つフラグを1それ以外を0とすれば、
 
 条件Aのフラグ     0  1  0  1
 条件Bのフラグ     0  0  1  1
 AかつBをみたす?   0  0  0  1 
 
となり、かけ算したときの計算の結果と同じです。これを論理積と言い、その筋の学問の記号では∧と表します(集合の積集合の記号∩に似ていますが、0か1の2値しかないので、どちらかに決まるということで尖っていると思ってください)。
 
また、同様に「または」、というのもありますが、表にすると
 
 条件Aのフラグ     0  1  0  1
 条件Bのフラグ     0  0  1  1
 AまたはBをみたす?  0  1  1  1
 
となり、かけ算したとき計算の結果と同じです。これを論理積と言い、その筋の学問の記号では∨と表します(∧と同様に集合の和集合の記号∪に似ていますが、はやり、論理式では0か1の2値しかないので、どちらかに決まるということで尖っているわけです)。
 
他に、もちろん、否定(記号:¬)と言うものもありますが、これは
 
 条件Aのフラグ     0  1
 条件Aの否定      1  0
 
と、わかりやすいです。
 
こういう数式を扱う学問にブール代数というのがあるのですが、言語の中には0をFalse、1をTureと表現する、ブーリアン型というのがあります。これはブール代数からきているわけですね。
 
だから、プログラム言語によっては、分岐の条件の部分で0以外の値にすればとすれば常に真と判断するという言語もありまして、慣れないととわかりにくいバグになりますから、気をつけてくださいね。
 
以上です。
 
最後まで地味なこの講座にお付き合いいただきまして本当にありがとうございました。まだ、葉桜の咲くこの時期にこうして一つ書き物を終了させることができたことを本当にうれしく存じます。
 
つたない講座でしたが、何とか終わらせることができましたのはみなさまのご声援と叱咤激励の賜であり、繰り返しになりますが、心より感謝の意を表させて頂きます。
 
                             平成26年4月吉日

2014年4月5日土曜日

人で無しのための計算機理論入門 その9 プログラムの基礎 その3 使い回して効率を上げよう

がんばるためにがんばる、そんな訳の分からない状況で、貧乏なのに国のためにボランティアをやっている、なんだか訳の分からない私。しかし、「世界市民のみなさん。アメリカがあなたのためになにをしてくれるかではなく、人類の自由のために共になにができるかを考えようではありませんか」とは故ケネディ大統領の有名な演説にもある通り。少なくても今までこの国でも人権さえも無視されてきても、ホモサピエンスには違いありませんので、気持ちだけでも人類の自由のために微力を尽くそうという次第。
 
※ ところで、一つ訂正があります。「その3」にて、C/C++、Javaなどの高級言語のことを関数型と申し上げていましたが、オブジェクト指向型と申し上げるべきでした。お詫びして訂正いたします。ブログの方の記事においては訂正済みです。
 
さて、今回はサブルーチンについてお話しします。
ある程度プログラムが書けるようになって、いろいろなプログラムを書いているうちに、あれ、これってどこかで同じプログラムを書いたな、とか、この部分は他でも何回も使うんだけど、いちいち同じことを書いたりするの面倒だな、という気になってきますよね。
そういうときに、その部分だけを独立させて使い回すことをサブルーチン化すると言います。考え方としては、木の幹、いわば幹線的な処理を行う部分をメインルーチン、そこから呼び出されて様々な専門的に特化した仕事を繰り返し行うところをサブルーチンといいます。

以前、「その7」で説明した、フローチャートの記号は以下のようになります。


現在主流のオブジェクト指向型言語では、サブルーチンの処理をクラス(class)として、独立させることが主流です。
 
どのように独立させるかというと、
 
 1.サブルーチンの中で使用する変数とその中で行う処理を
   他から影響されない一つの独立した組にする。
  (カプセル化)
 2.似たようなサブルーチンは、同じクラスの中で、
   異なるメソッド(method)と記述し、呼び出すときは、
   [クラス名].[メソッド名]のようにして呼び出す
 
といった感じでしょうか。ちなみに、クラスの中の変数にも、
 
   [クラス名].[変数名]
 
という感じで呼び出せるものもあります。(呼び出せないものもあります。これについては後述します)
 
このような、
 
 [クラス名].[メソッド名]や、
 [クラス名].[変数名]
 
で呼び出せるものを、メンバ(member)と呼びます。3年B組の誰々さんを呼び出すのとちょっと似ていますよね。
 
一般にクラスの中だけで使う変数や、サブルーチンなどは、プライベート(private)と分類され、クラス外側から見えないようにします。クラスの外側から見えてもいいものをパブリック(public)に分類します。
 
このあたりのことは、言語の仕様にも依る部分があるので、詳しくはその言語の使用をよくご確認下さい。
ただ、プロセスが分かっていると、クラスに関しても何となくよく分かりますよね。
 
さて、このように、誰にだって、(コンピュータのプログラムにだって!)プライベートはあるんです。私にはありませんけど……。

2014年4月3日木曜日

人で無しのための計算機理論入門 その8 プログラムの基礎 その2 変数とメモリの関係

もう書かなくて良いのかと思っていたら、なんだか書かないといけないような雰囲気。四月バカであるように祈りたいです(この部分は4月1日に書いています)。しかし体調はいまいちなんだけどねえ。また使いつぶされてる為の陰謀じゃないのか、と半分本気で疑っている現在。みなさまどうお過ごしでしょうか。

(※4月3日注記 などと書いていたら4月2日のニュースで、オバマ大統領の訪日決定しそうだとあり、かなりビクビクているところ。私なりに大急ぎで仕上げたのは言うまでもありません)

さて、分岐ができればループができるということは前回の図でもおわかりいただけるのではないかと思います。

となると、他にいくつかの予備知識が有れば、もう、プログラムも書けるんじゃないかな、と思うでしょう。かけると思うけど、世の中そんなに甘くはないけど、結構甘い。どっちなんだ。

あと二つ、いや、三つかな、お話しすれば、関数型と言われる言語であれば、そこそこなプログラムは書けるになると思います。多少、経験は必要でしょうが。

まず、前回のフローチャートで、変数を使っていますが、意味的にはおわかりいただけたでしょうか。
 
たとえば、

  i=i+1

などというのは、計算機プログラム上よく出てくる表現ですが、これは、もともと、計算機のメモリのある番地の内容を変数iとして使用しますよ、ということから出てくる、一般的な数学では見かけない表現で、要するに変数iとして割り当てられたメモリの内容を1増やしなさいということを計算機に指示する表現です。

 この命令は、計算機内部では、メモリの内容をCPUのレジスタに読んでそのレジスタの内容を一増やして、もとのメモリの番地に書き込むという作業が行われるわけですが、それ以前の重要な問題がありますよね。

すなわちまず、ある変数をメモリに割り当てる、という命令がたいていのコンピュータ言語では必要となります。(Rubyという言語では勝手にそのあたりの空気を読んでこっそりとやってくれたり、それ以外の言語でも、統合開発環境と呼ばれるプログラム作成用のアプリケーションソフトを使えば、プログラムの作成中に指摘してくれたりもするようですが)たとえば、C/C++と言われる言語であれば、

 int i;

と、変数を宣言します。これは、C/C++言語では「変数iを整数型の変数として宣言します」と言う意味ですが、実際のプログラムの実行上はメモリのある番地に整数の変数iの内容を記憶する領域を確保して下さいね、と言う意味です。(なんだかちょっとプロセスというのが分かってきたでしょう?)

つまり、プロセスというのは、プログラムが実際CPUで実行される形式(これを機械語、あるいはマシン語とも言います)で表現されたプログラムと、このような変数の為のメモリの領域が確保されたものということです。

さて、プロセスが分かっていただいたところで、この節での大きな一つの目的は果たしたわけですが、せっかくだからもう少しプログラムを書く上で重要なことを説明しておきましょう。ここからは少しややこしくなりますので、分からなくてもかまいません。しかし、知っていると、後々プログラムを書く技法上でのいろいろな悩ましいことがらでスマートに解決できる、という点で違ってきますので、一応説明します。

上記の例で、変数iをメモリのある番地の内容とすることにしました。ところで、その変数iの内容がどの番地にあるかということをどこかに記憶しておかなければ、高級言語から機械語に翻訳するときなどで困ります。

C/C++言語などで言われる、いわゆるポインタというものです。

たとえば、変数iの内容を変数jと同じ内容にしますということを行うときに、我々は変数iが変数jと同じになればいいんだから、たとえば、

 i=j

と表現すればそれで良いと考えますが、しかし、よくよく考えるとコンピュータでは、実は基本的には二種類のやり方があって、
 
1.変数iと変数jの内容を記憶するメモリの領域を
  別々に二つ確保して、変数iの内容を変数jと同じにする

2.変数jの内容を記憶するメモリの領域を一つだけ確保し、
  変数iは、変数jの番地と同じ番地を参照するようにする

という、非常に微妙な話があります。

1.を「値渡し」あるいは「内容渡し」、2.を「参照渡し」もしくは「ポインタ渡し」と言います。

一般的なコンピューターの高級言語は、変数と変数において「値渡し」であり、「参照渡し」は特別な指示をしないとできなかったり、そもそもサポートしていなかったりしますが、次回説明する予定のサブルーチンに値を渡すときに、言語によって元々の設定が「値渡し」か「内容渡し」かが異なりますから注意しておかないといけません。

「値渡し」であれば、たとえば、上の例では、
 
 i=j

としたあとは、それぞれ独立した変数になりますが、「参照渡し」であるときには、iの内容だけを変更しようとしてjの内容まで変更する、ということが発生しますからね。

このあたりは本当にややこしくて、注意していないとバグ(コンピュータプログラムが考えているとおりに動かないときのミスをバグが紛れ込んでるという言い方をします)としても発見できにくいバグになりやすいので、「値渡し」か「参照渡し」かは、少しプログラムが書けるようになってきたら、で良いですので、いつも気をつけておいて下さいね