NOT / XOR の真理値表
NOT / XOR の真理値表
このレッスンで分かること
XORは「違い」を表す演算- 単項演算
NOT aと 二項演算a XOR bを表で整理すると次のとおりですNOTは単にTrueとFalseを入れ替えるだけです
NOT / XOR の真理値表 とは
2 つの真偽値 (0/1) を受け取り、NOT a と a XOR b の結果を 2 ビットに詰めた整数で返す関数を実装します。
前のレッスンでは AND と OR を扱いました。今回は残る 2 つの基本演算、NOT (論理否定) と XOR (排他的論理和) を学びます。NOT は 1 つの真偽値を反転する単項演算で、XOR は 2 つの真偽値が「ちょうど 1 つだけ True」のときに True を返す二項演算です。AND OR NOT の 3 つだけがあれば全ての真偽値関数を作れますが、XOR を加えるとパリティ判定や暗号、ハッシュなどがぐっと書きやすくなります。
本章では NOT a と a XOR b を 1 つの関数で計算し、2 ビット整数に詰めて返します。bit1 に NOT a、bit0 に a XOR b を入れる設計です。これは Java の配列返却に依存しないシンプルな API で、4 言語すべてで同じ書き方ができます。
NOTは単項、XORは二項。ANDORの双子のような演算で、組み合わせると不思議な性質がたくさん出てきます。
真理値表
単項演算 NOT a と 二項演算 a XOR b を表で整理すると次のとおりです。
| a | b | NOT a | a XOR b |
|---|---|---|---|
| F | F | T | F |
| F | T | T | T |
| T | F | F | T |
| T | T | F | F |
NOT は単に True と False を入れ替えるだけです。XOR は左右が「異なるとき」に True を返すので、「ちがい検出器」として使えます。たとえば 2 つのビット列をビット単位で XOR すると、違いがある位置だけ 1 になるため、差分検出やフリップビット計算に使えます。
Python
print(not True) # False
print(not False) # True
print(True ^ False) # True (Python では XOR は ^)
print(True ^ True) # FalseJavaScript
console.log(!true); // false
console.log(true !== false); // true (XOR の代用)
console.log((true ? 1 : 0) ^ (false ? 1 : 0)); // 1Python には xor キーワードはなく、ビット演算 ^ を真偽値にそのまま使えます (True は 1、False は 0 として扱われます)。JavaScript は論理 XOR 専用の演算子がないので、a !== b で代用するか、整数化してから ^ を使います。
NOT と XOR のフロー
図のポイント (テキスト併記)
XORの重要な性質として、a XOR a = 0a 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 xはbool(x)と同じ意味。
よくある間違い
1 つめは、Python で ^ を「べき乗」だと勘違いするケースです。Python のべき乗は ** で、^ はビット単位の XOR です。2 ^ 3 は 1 (ビット 10 XOR 11 = 01) になりますので、誤って 2 ^ 3 == 8 だと思うと痛い目を見ます。2 つめは、JavaScript で ! を二項演算子に書こうとするケース。! は単項、!= !== は不等価です。3 つめは、Java の ^ を boolean 同士に使うと論理 XOR として動きますが、int に対して使うとビット演算になることを混同するケースです。
やってみよう
2 つの真偽値を 0/1 で表した a b を受け取り、NOT a を bit1、a XOR b を bit0 に詰めた整数 ((NOT_a << 1) | XOR) を返す関数 notXor(a, b) を実装します。a = 0, b = 0 なら NOT a = 1, XOR = 0 で結果は 0b10 = 2、a = 1, b = 0 なら NOT a = 0, XOR = 1 で結果は 0b01 = 1 です。4 通りの入力ですべて真理値表どおりの結果が返れば合格です。NOT a の判定は a == 0 ? 1 : 0 のように三項で書くのが分かりやすいでしょう。XOR は a != 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 つができることを確認しましょう。
- NOT / XOR の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. NOT / XOR とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
- NOT a と a XOR b を 1 つの関数で計算する
- NOT a を bit1、XOR を bit0 に詰める
- 真理値表に従った結果になる
入出力例
test-cases.txt
notXor(0, 0) → 2
notXor(0, 1) → 3
notXor(1, 0) → 1
notXor(1, 1) → 0