見出し画像

シアトルで実践する「プログラミング的思考」[11] 論理的に考える(2)ロジックを使う

論理的に考える(その1)では「論理的にアルゴリズム設計をする」ことを解説しました。ソフトウェアエンジニアが「重複がなく、なおかつ問題の全てを網羅する」よう論理的にアルゴリズムを設計することを取り上げました。

ここでは「論理的に考える」という思考はもちろんですが、さらに「論理を使う」場合について解説します。具体的には条件文と呼ばれる制御構造でどのようにロジック(論理)が利用されるかを見ていきます。

条件文のおさらい

アルゴリズムは様々な制御構造を使ってステップの流れをコントロールします。それぞれのステップでなんらかの動作を行うわけですが、中でも条件文と呼ばれる制御構造の仲間は「条件を表す式」と「動作を示すステップ」とを合わせて記述します。

コンピュータがそのステップを実行するかどうかはその式の評価結果に完全に依存します。実行時に式を評価し、その結果が「真」の値をとれば「条件を満たしている」と判定し、ステップが実行されるのです。結果が「偽」の時はステップは実行されません。

条件文にはいくつかのバリエーションがありますが、式が実行の流れを決定する点では同じです。こういった仕組みはロジック (logic)と呼ばれ、論理学を基礎にしています。「こうだったら、こうする」という風な「ルール」と理解してもいいでしょう。

条件を式で表す

コンピュータが実行できるようにプログラミング言語でアルゴリズムを記述する時、制御構造で使われる条件は「評価式(もしくは式)」を使って表します。最も単純な評価式の例としては「真」を表す true という予約語か、「偽」を表す false という予約語を条件文にそのまま使うものです。「if (false) ステップ」という表記になります。これは文法的に正しい文ですがあまり意味がありません。いつも無条件に「偽」として評価されるので「条件文」ではありません。

注1:予約語とはそのプログラミング言語がすでに使うことにした言葉で、他の目的には利用できません。if なども予約語です。

注2:「偽」を表す予約語はプログラミング言語によって異なります。英語で「偽」を表す false がよく使われます。「真」を表す予約語は true であることが多いです。

等価を評価する式

次に、ほんの少し複雑な評価式として「ふたつの値が等しいかどうかを比べる」があります。「年齢 = 20」という感じで表します。実際に使う記号は、プログラミング言語によって異なりますが、どのプログラミング言語にも必ずこの式はあります。等しいかどうかを評価することを「等価演算」と呼びます。「等価演算をせよ」とコンピュータに命令するためには「等価演算子」という記号(例えば = や == など。プログラミング言語によって異なる)を使います。等価演算式の評価結果は「真」か「偽」になるので、条件文の式として使えます。

等価演算の反対の「不等価演算」は、2つの値が異なるときに「真」になります。<> や != を不等価演算子として使うプログラミング言語が多いようです。ペアで覚えると良いでしょう。

比較を行う式

また、評価式には他にも「AはBより大きい」や「AはBと同じか大きい」などを表すものもあります。比較が「小さい」でも同じです。「年齢が18歳以上なら、自動車の運転免許の試験に申請できる」といった条件文の式を「年齢 >= 18」などと表します。全てのプログラミング言語には比較を行う式があると思って間違いないでしょう。2つの値の大きさなどを比べることを「比較演算」と言い、コンピュータに比較演算の実行を命令するのに「比較演算子」という記号を使います。「>」などが一般的ですが、やはりプログラミング言語によって異なります。

比較演算には「より小さい」と「以下」のバリエーションがある場合が一般的です。演算子は < と <= がよく採用されているようです。<= は「小さいもしくは等しい」の意味なのでわかりやすいですね。

論理演算

さらに複雑な式では、いくつかの評価式を「論理演算」として組み合わせてひとつの評価式にします。論理演算のためには「論理演算子」を使います。これはアルゴリズムで「論理を使う」ことの最も分かりやすいケースですね。例えば「等価演算式A」と「比較演算式B」があったとします。「AもBもどちらも真なら・・・」といった条件になるように論理演算子「AND」で組み合わせることが出来ます。「等価演算式A AND 比較演算式B」のように記述出来ます。この場合「AND」が論理演算子です。

良く使われる論理演算

論理演算にはいくつか種類があります。いずれも「論理演算子」を使って指定しますが、概念としては論理積、論理和、否定、排他的論理和、などがよく使われます。英語ではAND、OR、NOT、XORなどと表します。これらを疑似コードとして使って、例を見ていきましょう。

評価式Aと評価式Bが「どちらも真なら」という条件は「A AND B」で表せます。評価式Aと評価式Bが「すくなくともどちらか一方が真なら」という条件は「A OR B」で表せます。評価式Aが「真ではない」は「NOT A」もしくは「A NOT true」などの式で表せます。この3つが、コンピュータをプログラミングする際にもっとも頻繁に使う論理演算です。

たまに使われる論理演算

XORはちょっと変わっていますが、コンピュータでも特定の目的で良く使われる論理演算なので理解しておくと良いです。これは評価式Aと評価式Bが「異なる値なら」という条件を表します。どういうことかというと、(Aが真、Bが偽)と(Aが偽、Bが真)というふたつの組み合わせの場合のみ、結果が「真」になるのです。「A XOR B」という感じで表記します。具体的な利用例はここで解説すると長くなるので、興味がある人は「XOR交換」で検索してみてください。

論理積(AND)を使ってひとつだけ具体的な例を考えてみましょう。あるロールプレイングゲームで、キャラがダメージを受けた際に「ライフがゼロでなおかつ所有する妖精の数がゼロならゲームオーバー」という条件をチェックしてゲームの進行を制御するとします。「なおかつ」という表現は「どちらも真」という意味なので「論理積(AND)」を使います。疑似コードは「if (life = 0 AND count of fairy = 0) then end game」という感じになるでしょう。ORやNOTなど、他の論理演算の使用例についてはここでは割愛します。

ところで論理学で習った人は、論理包含(=> などの記号で表され、 implies とも呼ばれる)もプログラミングで使うのか疑問に思うかもせれません。これは、一般的にソフトウェア開発で利用されているプログラミング言語では必要ありません。(習ったことがない人は気にしないでください。)

再度強調しますが、これら演算子はプログラミング言語によって異なります。ですが論理演算はコンピュータの、とくにアルゴリズムの核心にあたります。殆どの実際に稼働しているコンピュータは論理演算が出来ます。また殆どすべてのプログラミング言語には論理演算子があると理解して問題ないでしょう。

ロジックでビジネスルールを実装する

論理演算はビジネスルール(ビジネスロジックとも呼びます)を実装するためにも使います。ビジネスルールとは人間社会のルールです。例えば遊園地の乗り物の「年齢が5歳以上か身長が110センチ以上」という制限などです。乗り物の種類によって制限が変わる、人間が定めるルールです。この遊園地の乗り物の制限を論理演算式で表すと「年齢が5歳以上 OR 身長が110センチ以上」となります。どちらかの条件を満たしていればOKで、両方の条件を満たしている場合も当然OKとなります。

ビジネスルールの例をもう一つ見てみましょう。例えばある保険に加入するための条件が「喫煙しない、なおかつ現在入院していない」だとします(私が適当に考えた条件なので現実的では無いかもしれません)。この場合は論理演算子 AND を使って「喫煙しない AND 現在入院していない」と言うふうになるでしょう。ところで「喫煙しない」を現す式は比較演算子を使って thisYear - lastYearSmoked > 10 などと表すかも知れません。この場合タバコをやめて10年経っているかどうかで喫煙者かどうかの判定をしています(今が2020年として、最後にタバコを吸ったのが2015年なら、5 > 10 の評価結果は「偽」になります)。

ビジネスルールを論理演算式として表すのは少し難しく感じますね。実際プログラムのバグの1種として「ロジックエラー」と言うものがあります。これはコーディングしたロジックが実際のロジックと違う時に起こるプログラムの不具合です。(この種類のバグを抑え込む施策として「ユニットテスト」というものがあります。別の記事で紹介する予定です)

ブール型のブール値

条件として使う評価式はどれも、評価結果が「真か偽(true or false)」のどちらかの値になることはここまでの説明でお分かりになる通りです。このような値のことを「ブール値」と呼びます。どんなに複雑な論理演算でも、コンピュータは最終的にはひとつに集約されたブール値を結果として算出します。

「プール値」であるデータは「ブール型である」と言ったりします。例えば「外国人である」ことを示す isAlien というデータがあったとき、そのデータ型は「ブール型」です。ブール型も、プログラミング言語によって表記の仕方は異なります。しかし全てのプログラミング言語にブール型はあります。

ブール値はロジックを動かす血液のようなものです。それぞれの式がブール値を結果にとり、それらを論理演算子が結んでさらに新しいブール値結果が得られます。末端の式から評価を続けることで、どんな複雑な式の組み合わせも(論理式としてエラーが無いならば)最終的にはひとつのブール値に収束します。その最終的な値が条件文の条件として使われ、動作の有無を決定づけるのです。

この記事が気に入ったらサポートをしてみませんか?