※この記事は、論理演算と計算の優先順位に関する記事の後編です。前編はこちら。
論理演算をしてみよう
比較演算の次は、論理演算に移りましょう。
そもそも「論理演算」って何ですか? 今一つピンときません……。
簡単に言うと、true, falseを用いた、論理に関する演算を行なうもののことです。
な、なるほど……?
論理演算子にはいくつかあるのですが、今回は「!」「&&」「||」を学んでいきましょう。
お、お手柔らかにお願いします!
はい。まずは先ほども出てきた「!」から。「!」は否定(NOT)の意味があります。
void main(){
print(!true);
print(!false);
}
へー、「!」は真偽値の前にくっつけるんですね。
はい。このプログラムの実行結果はどのようになるでしょうか?
うーん……。否定ってことは、「じゃない」って意味ですよね……。「!true」は「trueじゃない」だからfalseで、「!false」は「falseじゃない」だから、trueですか?
実行結果false
true
true
正解です。「!」を翻訳するなら、「逆転させます」くらいの意味になりますね。
「!」はノット、逆転させる……覚えました!
「逆転させる」という考え方ができるのが、bool値のミソです。bool値以外の型は、逆転させることができません。
「!123」とか「!"あいうえお"」とか、意味わかんないですもんね。「123じゃないもの」「あいうえおじゃないもの」なんていくらでもありますし……。
そうなんですよ! これがわざわざ2択の型が設けられている理由です。trueでなければ絶対にfalse、falseでなければ絶対にtrueです。これは2択以外の型では不可能なことであり、この単純な事実が非常に大事です!
整数を使えば何択問題にだってできるのに、あえて「はい」「いいえ」の2択にするなんて不便じゃないのかな? って思ってました。でも、「逆転」がしたかったんですね!
実は、昔のプログラミング言語ではboolの考え方はありませんでした。整数値を用いて0か(X == 0)、0以外か(X != 0)を代わりに使っていたんです。
世の中には2種類の男しかいない。俺か、俺以外か。(キリッ)
それローラ○ドさんじゃないですか! ……こほんっ。
(先生、思ってたよりノリノリだ……)
整数ではNOTに相当するものが存在せず不便だったんですね。0の反対は何? ってなっちゃいますから。
それがきっかけでboolが誕生したというワケですね!
正確なところはわかりませんが、おそらくそういう経緯があったのでしょうね。
では次は「&&」です。以下のプログラムとその実行結果を見てみてください。
void main(){
print(true && true);
print(true && false);
print(false && true);
print(false && false);
}
実行結果true
false
false
false
false
false
false
えー!? 何ですか、これ!
落ち着いて、よく観察してみましょう。
左がtrueならtrueを返すってわけでもないし……。うーん……。
「true && true」とその他の違いは何でしょうか?
あ、「true && true」以外、全部falseになってます!
その通りです。「A && B」は「AかつB」で、「AND」の意味ですね。「「A・B」は両方ともtrueですか」と翻訳できます。
だから、片方だけでもfalseだと実行結果がfalseになっちゃうんですね。
はい、その通りです。「&&」は、左右が両方trueの時だけtrueを返します。
でもこれ、どういう時に使うんですか?
いい質問です。姫野さんはインターネットサービスの会員登録をする時、氏名や住所などの必須項目を入れ忘れてしまったことがありますか?
あ、やったことあります……。いっぱい入力したのに、「次へ」を押したら「必須項目を入力してください」とか言われて、ゼロからやり直しになって泣きました。
それならイメージしやすいですね。例えば「氏名が入力されている && 住所が入力されている && 電話番号が入力されている」がtrueであれば、次の画面に進めるというわけです。「&&」のイメージはつかめましたか?
はい! 何となくですが!
では次に、「||」を見ていきましょう。
「|」って何て読むんですか?
「バー」と読む人もいれば、「縦棒」と読む人もいますね。
ばーばーたてぼう。
それでは、「||」の意味を考えてみてください。
void main() {
print(true || true);
print(true || false);
print(false || true);
print(false || false);
}
実行結果true
true
true
false
true
true
false
ええと、さっきと逆……? ではないですね。わかるような、わからないような……。
じっくり観察してみましょう。実行結果がfalseになっているのはどんな時ですか?
……あ、わかりました! trueがない時ですね!
その通りです。ということは、「A || B」はどのように翻訳できるでしょうか?
A・Bのどっちかにtrueがありますか、とかですか?
素晴らしいです。「A || B」は、「「A・B」はtrueを含みますか」と翻訳できます。
やったー!
「||」は「AまたはB」、すなわち「OR」の意味で、片側にtrueを含んでいれば、もう片方がtrueでもfalseでも、必ずtrueを返します。
オアの演算子はわかりやすいですね!
「&&」も「||」も使いこなせるようにしましょうね。数学の命題や集合に応用することができます。
計算の優先順位
先生、今までに出てきた演算子の練習問題とかありますか?
姫野さんは向学心があってとても素晴らしいです。では、こちらのプログラムの実行結果を予想してみてください。
void main() {
print(123 == 123 && 123 != 123);
}
うーん……。演算子が3つもありますよね? どこから計算すればいいんですか?
非常にいい質問です。基本的には左側から計算するのですが、演算子には優先順位が存在します。例えば、「==」「!=」は「&&」「||」よりも優先順位が高いです。
なるほど……。そうすると、「&&」の左にある「123 == 123」から計算するってことですね!
その通りです。
「123 == 123」は、「123は123と同じですか」ですよね。同じだからtrueっと。
この時点の状況は、 print(true && 123 != 123); となりますね。
確かに! それで次は……「&&」と「!=」では「!=」のほうが優先順位が高いから、「123 != 123」を計算するんですね。「123は123と異なりますか」なのでfalseですね!
そうなります。すると、print(true && false); という状況になります。
わかりやすい! 「true && false」ってことは、「true・falseは両方ともtrueですか」って意味で、片方falseになっちゃってるから……答えはfalseですか!?
正解です!
やったー! 先生のおかげでちょっとわかってきた気がします!
では続けて2問目。
わかりました、どんどんいきましょう!
void main() {
print(123 < 123 || 123 <= 123);
}
「<」と「<=」も、「&&」や「||」より優先順位が高いんでしょうか?
仰る通りです。初めに演算するのはどこでしょう?
「123 < 123」ですかね、一番左にあるし。123は123より小さくないからfalseです。
いいですね。この時点での状況は、print(false || 123 <= 123); となります。
次に計算するのは「123 <= 123」ですね! 123は123以下だから、こっちはtrueになります!
その調子です。状況としてはprint(false || true); となりますね。
……あ、わかっちゃいました! 「false・trueはtrueを含みますか」ってことだから、答えはtrueですよね!?
はい、正解です。よくできましたね。
やっぱりわたし、天才なんじゃ……?
そ、そうですね……。
(ドヤァ)
計算式が順次、計算済みの値に置き換わっていくイメージを持っていただけると、難しい問題であってもわかりやすくなります。このイメージを持つことが非常に大事で、この先のプログラミング人生を左右すると言っても過言ではありません。
えぇっ、ちょっとそれは大袈裟じゃないですか?
少し大袈裟に聞こえるかもしれませんが、ぜひ初心者のうちにこそ覚えておくべきことのひとつですよ!
問題にチャレンジ!
天才の姫野さんのために、プログラムの実行結果を予想する練習問題を、あと5つ用意しました。
ひええ、5つも……!? が、頑張ります!
void main() {
print( (true != !true) && (true || true) );
print(!false || (!true || false ) );
print(12 * 3 == 30 + 6 && (!false != true) );
print( (false != true) || 12 + 3 == 123);
print(!( !( !( !( !true ) ) || !( !( !( ! false) ) ) ) ));
}
うわあ、どれも難しそう……。
今までやってきたことの積み重ねでしかありません、一つ一つこなしていきましょう。
まず1問目、print( (true != !true) && (true || true) ); はどうなるでしょうか? 今までのことを思い出して、自分で考えてみてください。
まず1問目、print( (true != !true) && (true || true) ); はどうなるでしょうか? 今までのことを思い出して、自分で考えてみてください。
ええと……。
まず「&&」の左側の丸括弧から計算します。「true・trueの逆転のfalseは異なりますか」だからtrueですね。これを①とします。
次に「&&」の右側の丸括弧を計算します。「true・trueはtrueを含みますか」だからtrueですね。これを②とします。
①と②から、「true && true」になるので、これを計算すると「true・trueは両方ともtrueですか」だから……答えは、trueです!
まず「&&」の左側の丸括弧から計算します。「true・trueの逆転のfalseは異なりますか」だからtrueですね。これを①とします。
次に「&&」の右側の丸括弧を計算します。「true・trueはtrueを含みますか」だからtrueですね。これを②とします。
①と②から、「true && true」になるので、これを計算すると「true・trueは両方ともtrueですか」だから……答えは、trueです!
はい、答えはtrueで合っています。
数学のテストはいつも平均いくかいかないかくらいでしたけど、証明問題みたいで楽しいですね! 証明問題が楽しいなんて思わなかったなー。
姫野さんの説明はおおむね正しいのですが、より厳密に説明すると次のようになります。
何かカッコいいですね……! 何ていうか、プログラミングって感じ!
では、この調子で2問目以降も解いていきましょう。
わたしなりに頑張ってみます!
void main() {
print(!false || (!true || false ) );
print(12 * 3 == 30 + 6 && (!false != true) );
print( (false != true) || 12 + 3 == 123);
print(!( !( !( !( !true ) ) || !( !( !( ! false) ) ) ) ));
}
姫野さん、いかがでしたか?
どの問題も結構考えましたけど、何とか解けました……!
それはよかったです。今回学んだ内容は、プログラミング人生において毎日向き合うと言っても過言ではないほどによく使うので、ぜひマスターしてくださいね。
はい、しっかり復習しておきます!