NOT / XOR の真理値表

生田 陸人
LuaGate エンジニア / 現役エンジニア
編集 LuaGate編集部

NOT / XOR の真理値表

このレッスンで分かること

  • XOR は「違い」を表す演算
  • 単項演算 NOT a と 二項演算 a XOR b を表で整理すると次のとおりです
  • NOT は単に TrueFalse を入れ替えるだけです

NOT / XOR の真理値表 とは

2 つの真偽値 (0/1) を受け取り、NOT a と a XOR b の結果を 2 ビットに詰めた整数で返す関数を実装します。

前のレッスンでは ANDOR を扱いました。今回は残る 2 つの基本演算、NOT (論理否定) と XOR (排他的論理和) を学びます。NOT は 1 つの真偽値を反転する単項演算で、XOR は 2 つの真偽値が「ちょうど 1 つだけ True」のときに True を返す二項演算です。AND OR NOT の 3 つだけがあれば全ての真偽値関数を作れますが、XOR を加えるとパリティ判定や暗号、ハッシュなどがぐっと書きやすくなります。

本章では NOT aa XOR b を 1 つの関数で計算し、2 ビット整数に詰めて返します。bit1NOT abit0a XOR b を入れる設計です。これは Java の配列返却に依存しないシンプルな API で、4 言語すべてで同じ書き方ができます。

NOT は単項、XOR は二項。AND OR の双子のような演算で、組み合わせると不思議な性質がたくさん出てきます。

真理値表

単項演算 NOT a と 二項演算 a XOR b を表で整理すると次のとおりです。

abNOT aa XOR b
FFTF
FTTT
TFFT
TTFF

NOT は単に TrueFalse を入れ替えるだけです。XOR は左右が「異なるとき」に True を返すので、「ちがい検出器」として使えます。たとえば 2 つのビット列をビット単位で XOR すると、違いがある位置だけ 1 になるため、差分検出やフリップビット計算に使えます。

Python

print(not True) # False print(not False) # True print(True ^ False) # True (Python では XOR は ^) print(True ^ True) # False

JavaScript

console.log(!true); // false console.log(true !== false); // true (XOR の代用) console.log((true ? 1 : 0) ^ (false ? 1 : 0)); // 1

Python には xor キーワードはなく、ビット演算 ^ を真偽値にそのまま使えます (True1False0 として扱われます)。JavaScript は論理 XOR 専用の演算子がないので、a !== b で代用するか、整数化してから ^ を使います。

NOT と XOR のフロー

diagram (will load when visible)

図のポイント (テキスト併記)

  • XOR の重要な性質として、a XOR a = 0 a XOR 0 = a という 2 つがあります

XOR の重要な性質として、a XOR a = 0 a XOR 0 = a という 2 つがあります。これを応用すると「同じ値を 2 回 XOR すると元に戻る」性質が得られ、ストリーム暗号や Gray code の生成、配列内で重複しない要素を探すアルゴリズムなどに使われます。

XOR は「違い」を表す演算。同じものは打ち消し、異なるものだけを浮き上がらせます。

NOT を多用しない読みやすさ

NOT は便利ですが、多用すると条件式の意味が反転して読みづらくなります。not (x > 0)x <= 0 は同じ意味ですが、後者の方が一目で意図が分かります。同様に not (a and b)ド・モルガンの法則not a or not b に変形できます。これは次のレッスンで詳しく扱う重要な等価変形です。

Python

x = 5 print(not (x > 0)) # False print(x <= 0) # False (同じ)

not を 2 つ重ねるとブール変換になる。 not not xbool(x) と同じ意味。

よくある間違い

1 つめは、Python^ を「べき乗」だと勘違いするケースです。Python のべき乗は ** で、^ はビット単位の XOR です。2 ^ 31 (ビット 10 XOR 11 = 01) になりますので、誤って 2 ^ 3 == 8 だと思うと痛い目を見ます。2 つめは、JavaScript! を二項演算子に書こうとするケース。! は単項、!= !== は不等価です。3 つめは、Java^boolean 同士に使うと論理 XOR として動きますが、int に対して使うとビット演算になることを混同するケースです。

やってみよう

2 つの真偽値を 0/1 で表した a b を受け取り、NOT abit1a XOR bbit0 に詰めた整数 ((NOT_a << 1) | XOR) を返す関数 notXor(a, b) を実装します。a = 0, b = 0 なら NOT a = 1, XOR = 0 で結果は 0b10 = 2a = 1, b = 0 なら NOT a = 0, XOR = 1 で結果は 0b01 = 1 です。4 通りの入力ですべて真理値表どおりの結果が返れば合格です。NOT a の判定は a == 0 ? 1 : 0 のように三項で書くのが分かりやすいでしょう。XORa != b ? 1 : 0 で OK です。

よくある質問

Q. ビット演算は実務でいつ使いますか?

A. フラグ管理(permission の rwx)、画像処理(マスク)、ハッシュ計算の高速化などで使います。複数の真偽値を 1 つの整数にまとめると、メモリ削減と演算高速化の両方が得られます。例えば 8 個の権限を 1 byte で表せます。

Q. AND / OR / XOR の代表的な使い道は?

A. AND は「特定ビットの確認・抽出」(flags & PERM_READ)、OR は「ビットの立て上げ」(flags |= PERM_WRITE)、XOR は「ビット反転や暗号化」で使います。XOR は 2 回かけると元に戻る性質から、簡易暗号や両端ポインタの入れ替えなどに応用できます。

Q. シフト演算で割り算しても良いですか?

A. 正の整数の 2 のべき乗での除算なら x >> n と x / (1<<n) は同じ結果になります。ただし負の数では言語ごとに挙動が違う(算術シフトと論理シフトの区別)ため、可読性と安全性のために通常の演算子を使い、性能ボトルネックでのみシフトを検討してください。

次のレッスン

次は 含意 (→) を AND/OR/NOT で表現 に進みましょう。「a ならば b」の真偽の不思議さも体感します。

事前確認 — 進む前に次の 3 つができることを確認しましょう。

  1. NOT / XOR の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. NOT / XOR とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン

要件

  1. NOT a と a XOR b を 1 つの関数で計算する
  2. NOT a を bit1、XOR を bit0 に詰める
  3. 真理値表に従った結果になる

入出力例

test-cases.txt

notXor(0, 0)2 notXor(0, 1)3 notXor(1, 0)1 notXor(1, 1)0

ヒント

main.py
main.py
学習モード

メモ

NOT / XOR の真理値表

⌘S で保存