NOT / XOR の真理値表
「食い違っていたら」を AND と OR だけで書くと長い
2 つの設定が食い違っていたら警告を出したい。前回の道具だけで書くと、「片方が真でもう片方が偽、または、片方が偽でもう片方が真」と、両方の場合を並べることになります。条件が増えるほど、この書き方は伸びていきます。
食い違いをひと目で見る演算が XOR です。あわせて、真偽をひっくり返すだけの NOT も押さえます。
OR の表を 1 行だけ変えると、XOR になる
前回の OR は、両方が偽の行だけが偽で、あとは全部真でした。XOR はそこに「両方が真の行も偽」が加わります。変わるのは最後の 1 行だけです。
つまり XOR が真になるのは、真がちょうど 1 つのときです。言い換えると、2 つが違うときだけ真になります。ちがい検出器だと思ってください。
NOT のほうは入力が 1 つで、真を偽に、偽を真に入れ替えるだけです。表を書くまでもありません。
Python
print(True ^ False) # True 違う
print(True ^ True) # False 同じ
print(not True) # FalseXOR が効くのは、排他を確かめたいときです。「上書きと追記のどちらか一方だけを指定させたい」「新規と更新のどちらか一方だけが立っているはず」といった検査は、AND と OR を組み合わせて長く書くより、食い違いを 1 つの演算で見たほうが意図が残ります。両方指定も未指定も同じく弾きたい、という要求にそのまま重なります。
^ はべき乗ではない
Python で 2 ^ 3 を書くと、8 ではなく 1 が返ります。^ は XOR で、べき乗は ** です。数式の見た目に引きずられて ^ を書き、値が小さすぎることに何時間も気づかない、という事故がよく起きます。
JavaScript には真偽値どうしの XOR がありません。!== で代用するか、0 と 1 に直してから ^ を使います。真偽値をそのまま ^ に渡すと数として扱われるので、返るのも真偽値ではなく 0 か 1 です。返り値の型が変わる点に気をつけてください。
NOT は、重ねるほど読めなくなる
not (x > 0) と x <= 0 は同じ意味ですが、後者のほうがひと目で分かります。not not x に至っては、真偽値へ変換しているだけなのに、読む側は毎回立ち止まります。
否定は、書けるなら反対向きの比較へ書き換えたほうが後で困りません。条件式のレビューで指摘されるほとんどは、この読みにくさが原因です。
要件
- NOT a と a XOR b を 1 つの関数で計算する
- NOT a を bit1、XOR を bit0 に詰める
- 真理値表に従った結果になる
入出力例
notXor(0, 0) → 2
notXor(0, 1) → 3
notXor(1, 0) → 1
notXor(1, 1) → 0