Ruby
備忘録

論理演算子を論理学的に理解する

複雑な論理演算をするときには、いくつか注意することがある。
一つ目は、「演算子の優先順位」で、二つ目は「演算子の入れ替え」。

一つ目は簡単だが、演算子には優先順位がある。詳しくは以下URL。
https://docs.ruby-lang.org/ja/latest/doc/spec=2foperator.html

a && b || c
は、「aかつbが真、またはcが真のとき、真」を意味する。
「aが真かつ、bまたはcが真のとき、真」としたければ、
a && ( b || c )
とする。

二つ目は、上の式を否定したい時などに注意しなければならないことで、
「aかつbが真、またはcが真のとき、偽」としたければ、
! (a && b || c)
でもよいが、これは、
(!a || !b ) && !c
「aまたはbが偽かつ、cが偽のとき、真」と同値である。

具体例を考えれば、この同値関係は納得できるだろうが、プログラムを書いてる間にいちいち考えるのは面倒だ。そこで、論理学の公式を覚えておくと、具体的に考えずに、簡単に書き換えができる。
覚えておくとよい論理学の公式は以下の通りだ。

not not A = A
A and A = A (and の同一律)
A or A = A (orの同一律)
A and B = B and A (and の交換則)
A or B = B or A (or の交換則)
A and B and C = A and (B and C) (and の結合則)
A or B or C = A or (B or C) (or の結合則)
A and True = True and A = A
A and False = False and A = False
A or False = False or A = A
A or True = True or A = True
A or A and B = A and B or A = A
A and (A or B) = A and (B or A) = (A or B) and A = (B or A) and A = A
A and not A = not A and A = False (排中律)
A or not A = not A or A = True (排中律)
A and (B or C) = (B or C) and A = A and B or A and C (分配律)
A or B and C = B and C or A = (A or B) and (A or C) (分配律)
not(A and B) = not A or not B (ド・モルガン則)
not(A or B) = not A and not B (ド・モルガン則)

大体の公式は「当たり前」だ。覚えておくのは、最後の4つくらいだろう。これらを使って先ほどの例を考える。

! ( A && B || C)
= !( A && B ) && !C
= ( !A || !B ) && !C

となる。もっとややこしい状態を考える。
「A=Bが真であり、かつC=DまたはC=Eでないとき、ある処理を実行する」を作りたい場合、順番に、

sample.rb
if A == B 
 unless C == D || C == E
  #処理
 end
end

と書いてもいいが、あまり階層を作りたくないので、一つの式で済ませたい。
論理学の公式を使うと、
A=B && !(C=D || C=E)
は、
A=B && (C!=D && C!=E)
とできるので、

sample.rb
if A == B && (C != D && C != E)
 #処理
end

みたいにする。プログラムのif文は、「もし〜なら」で理解しておくより、「〜が真ならば」で理解しておいた方が、論理演算子の処理が楽になる。