- 技術 💻
XORとは?排他的論理和の真理値表と使い道|8言語とSQLで実行
結論
XOR(排他的論理和)は、2つの入力が「違うときだけ1(真)」になる論理演算です。同じ値で2回XORすると元に戻る性質があり、フラグの反転・パリティ・重複していない1つを探す処理などに使われます。
この記事でわかること
- XORの真理値表と、AND・OR・NOT・XNORとの違い
- Python・Java・C・JavaScript・SQLなど8言語とSQLで実行した結果
- ^をべき乗と取り違える誤り・優先順位の落とし穴と直し方
XORは「どちらか一方だけ」を表す演算です。1ビットの足し算の「和」の桁はXOR、「桁上がり」はANDで求まります。下の図は、その組み合わせ(半加算器)です。
flowchart TD
A[入力 A] --> X[XOR]
B[入力 B] --> X
A --> N[AND]
B --> N
X --> S[和 S<br>違えば1]
N --> C[桁上がり C<br>両方1なら1]
よく調べられることの答えを先にまとめます。
| 知りたいこと | 答え | 詳しい節 |
|---|---|---|
| XORとは | 入力が違うときだけ1になる演算。排他的論理和・EOR・EX-ORとも呼ぶ | XORとは |
| XORの真理値表 | 0と0→0、0と1→1、1と0→1、1と1→0 | XORの真理値表 |
| ORとの違い | 両方1のとき、ORは1、XORは0 | XORの真理値表 |
| 3つ以上のXOR | 1の個数が奇数なら1、偶数なら0 | 3入力以上のXORとベン図 |
| 排他的論理和の記号 | 数式は ⊕、多くの言語は ^、SQLは XOR や # | プログラミング言語別の書き方 |
| 2^10 が 8 になる | ^ はべき乗ではなくXOR。べき乗は ** や Math.pow | XORのよくある間違い |
| XORの使い道 | フラグ反転・パリティ・差分・重複していない1つを探す・グレイコード | ビット演算でのXORの使い道 |
| 2回かけると元に戻る理由 | 同じ値どうしのXORは0、0とのXORは元の値だから | XORの性質 |
確認環境:Ubuntu 24.04.5 LTS の上で、Python 3.13.18、Node.js v22.23.4、OpenJDK 21.0.12.1(javac・java)、gcc 13.3.0(C)、PHP 8.3.6、Ruby 3.3.6、rustc 1.97.0、GNU bash 5.2.21 の8つで同じ計算(5 ^ 3・負の数・真偽値・優先順位・小数)を実行し、出力とエラーの原文を写しました。SQL は PostgreSQL 16.15 を作業用のフォルダーに作り 127.0.0.1 だけで起動して試し、SQLite 3.53.1 は Python の sqlite3 モジュールで試しました。表計算の XOR 関数・BITXOR 関数は LibreOffice Calc 24.2.7.2 をヘッドレスで動かして結果を確かめ、Excel の仕様は Microsoft サポートの「XOR 関数」、MySQL の XOR 演算子は MySQL 8.4 リファレンスマニュアルで確かめました(Excel・MySQL は手元では動かしていません)。演算子の定義と優先順位は Python 言語リファレンス、MDN、PHP マニュアル、PostgreSQL 公式ドキュメントで確かめています。性質の確認(8ビットの全組み合わせ)と、重複していない1つを探す処理の速さ・メモリの測定は Python で行いました。図は mermaid 11.16.0 で描画を確かめています(確認日 2026年10月29日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「XORとは?排他的論理和の真理値表と使い道|8言語とSQLで実行」
XORとは(排他的論理和の意味・読み方・記号)
この節では、XORという言葉の意味と読み方、書き方の種類が分かります。
XOR(エックスオア)は eXclusive OR の略で、日本語では排他的論理和(はいたてきろんりわ)と呼びます。2つの入力のうち「どちらか一方だけ」が真のとき真になり、両方が真、または両方が偽のときは偽になります。EOR・EX-OR と書く資料もあり、どれも同じ演算です。
日常の言葉にすると「AかBのどちらか一方。ただし両方はなし」です。たとえば定食の「ご飯かパンをお選びいただけます」は、両方は選べないのでXORに近い意味です。一方、「経験者または資格保有者」の「または」は両方を満たしてもよいので、OR(論理和)です。
数式の記号
A ⊕ B。丸の中に+。論理学では A ⊻ B と書く本もある。
情報処理の試験は ⊕
プログラミング
a ^ b。C・Java・Python・JavaScript・Ruby・Rust・PHP・bash で共通。
べき乗ではない
SQL
MySQL は a XOR b(真偽)と a ^ b(ビット)。PostgreSQL は a # b。
製品ごとに違う
表計算
=XOR(論理式1, 論理式2, …) と、整数のビットごとに計算する =BITXOR(数値1, 数値2)。
TRUEの数が奇数ならTRUE
XORは、論理演算(真か偽かを組み合わせる計算)の1つです。コンピューターの中では真を1、偽を0で表すため、「1ビットどうしのXOR」=「足し算の1の位(繰り上がりを無視した和)」とも言えます。0+1=1、1+1=10(2進数)の1の位は0、という具合です。冒頭の図の半加算器は、この関係を回路にしたものです。
XORの真理値表(AND・OR・NOT・XNORとの違い)
この節では、XORの真理値表と、ほかの論理演算との違いが1つの表で分かります。
XORの真理値表は「0,0→0」「0,1→1」「1,0→1」「1,1→0」の4行です。ORとの違いは最後の行だけで、両方1のときORは1、XORは0になります。手元の Python で6種類の演算を計算した出力をそのまま載せます。
ops = {'AND': lambda a, b: a & b, 'OR': lambda a, b: a | b, 'XOR': lambda a, b: a ^ b,
'NAND': lambda a, b: 1 - (a & b), 'NOR': lambda a, b: 1 - (a | b),
'XNOR': lambda a, b: 1 - (a ^ b)}
print('A B | ' + ' '.join(f'{k:>4}' for k in ops))
for a in (0, 1):
for b in (0, 1):
print(f'{a} {b} | ' + ' '.join(f'{f(a, b):>4}' for f in ops.values()))
A B | AND OR XOR NAND NOR XNOR
0 0 | 0 0 0 1 1 1
0 1 | 0 1 1 1 0 0
1 0 | 0 1 1 1 0 0
1 1 | 1 1 0 0 0 1
| 演算 | 1になる条件 | 記号・書き方の例 | ひとことで |
|---|---|---|---|
| AND(論理積) | 両方1 | A・B、a & b | どちらも |
| OR(論理和) | どちらか1(両方でも1) | A+B、a | b | 少なくとも1つ |
| XOR(排他的論理和) | どちらか一方だけ1 | A⊕B、a ^ b | 違えば1 |
| NOT(否定) | 入力が0(入力は1つ) | ¬A、!a、~a | 反対にする |
| NAND(否定論理積) | 両方1以外 | ¬(A・B) | ANDの反対 |
| NOR(否定論理和) | 両方0 | ¬(A+B) | ORの反対 |
| XNOR(否定排他的論理和) | 両方同じ | ¬(A⊕B) | 同じなら1 |
ORとXORの見分け方
見分ける問い:「両方当てはまったとき、真にしたいか」
XORを論理式で書くと
XORは AND・OR・NOT の組み合わせでも表せます。よく使う形は次の2つで、どちらも同じ真理値表になります。
- A⊕B = (A・¬B)+(¬A・B):「Aだけ真」または「Bだけ真」。
- A⊕B = (A+B)・¬(A・B):「少なくとも1つ真」かつ「両方真ではない」。
MySQL のマニュアルも、a XOR b は (a AND (NOT b)) OR ((NOT a) and b) と数学的に等しい、と説明しています。XNOR は XOR の結果を反転したもので、「2つが等しいか」の判定そのものです。
3入力以上のXORとベン図(1の個数が奇数なら1)
この節では、入力が3つ以上のときのXORの結果と、ベン図での表し方が分かります。
3つ以上のXORは「1の個数が奇数なら1、偶数なら0」です。A⊕B⊕C は (A⊕B)⊕C と左から順に計算しても、A⊕(B⊕C) と右から計算しても同じ結果になります。8通りを計算した出力です。
A B C -> A^B^C 1の個数
0 0 0 -> 0 0
0 0 1 -> 1 1
0 1 0 -> 1 1
0 1 1 -> 0 2
1 0 0 -> 1 1
1 0 1 -> 0 2
1 1 0 -> 0 2
1 1 1 -> 1 3
注意したいのは、3入力のXORは「どれか1つだけ1」ではない点です。最後の行のように3つとも1でも結果は1になります。「ちょうど1つだけ」を判定したいなら、1の個数を数えて1と比べます。表計算の XOR 関数も同じ決まりで、Microsoft サポートは「TRUE と評価される入力の数が奇数なら TRUE、偶数なら FALSE」と説明しています。手元の LibreOffice Calc でも次のとおりでした。
XOR(1,0) -> TRUE
XOR(TRUE(),TRUE()) -> FALSE
XOR(TRUE(),TRUE(),TRUE()) -> TRUE
XOR(1,0,5) -> FALSE (0以外は真。真が2つで偶数)
BITXOR(5,3) -> 6
BITXOR(12,10) -> 6
ベン図で見るXOR(対称差)
ベン図では、XORは2つの円の「重なっていない部分」だけを塗った形になります。円Aだけの部分と円Bだけの部分が真、重なり(両方)と外側(どちらでもない)が偽です。集合の言葉では「対称差」と呼び、Python の集合では同じ ^ 記号で書けます。
print(sorted({1, 2, 3} ^ {2, 3, 4})) # 片方だけにある要素
[1, 4]
JavaScript でも Node.js 22 では new Set([1,2,3]).symmetricDifference(new Set([2,3,4])) が [ 1, 4 ] を返しました。Python の集合の演算は関連記事「Python setとtupleの違い|集合の使い方とlist・dict比較表」で、JavaScript の Set は関連記事「JavaScript Map・Set|使い方とObject・配列との違い一覧」で扱っています。
XORの論理回路(XORゲートと半加算器)
この節では、XORゲートの記号と、ほかのゲートからXORを作る方法、足し算の回路での役割が分かります。
XORゲートの記号(MIL記号)は、ORゲートの入力側にもう1本の弧を足した形です。出力側に小さな丸を付けると XNOR ゲートになります。部品としては、2入力のXORゲートを4個入れたIC(74HC86 など)が売られています。
XORは、NANDゲートを4個つなげても作れます。NAND だけでどんな論理回路も作れる(万能ゲート)ことの例としてよく使われる構成です。Python で組んで4通りを確かめました。
nand = lambda a, b: 1 - (a & b)
def xor_nand(a, b):
n1 = nand(a, b) # 1個目
return nand(nand(a, n1), nand(b, n1)) # 2〜4個目
print([xor_nand(a, b) for a in (0, 1) for b in (0, 1)])
[0, 1, 1, 0]
半加算器(1ビットの足し算)
和 S = A⊕B、桁上がり C = A・B。1+1 なら S=0、C=1 で、2進数の「10」になる。
全加算器(下の桁からの桁上がりも足す)
和 S = A⊕B⊕Cin。3入力のXORなので「1の個数が奇数なら1」。桁上がりは2つ以上が1のとき1。
何ビットもの足し算
全加算器を桁の数だけ並べる。CPU の足し算の回路の基本になる考え方。
CPU の命令にも XOR があります。手元の gcc 13.3.0 に int zero(void){ return 0; } を -O2 でコンパイルさせると、0を入れる処理が xorl %eax, %eax(自分自身とのXOR)になりました。自分とのXORは必ず0になる性質を、コンパイラーが「0を作る命令」として使っている例です。
zero:
endbr64
xorl %eax, %eax
ret
XORの性質(同じ値で2回かけると元に戻る)
この節では、XORの使い道の元になる性質と、それを全組み合わせで確かめた結果が分かります。
XORには「同じ値で2回XORすると元に戻る」性質があります。(a⊕b)⊕b = a⊕(b⊕b) = a⊕0 = a という順に、下の表の性質を組み合わせると説明できます。
| 性質 | 式 | 8ビットで確かめた組み合わせ | 結果 |
|---|---|---|---|
| 交換法則 | a⊕b = b⊕a | 65,536通り | すべて成立 |
| 結合法則 | (a⊕b)⊕c = a⊕(b⊕c) | 327,680通り | すべて成立 |
| 自分自身とは0 | a⊕a = 0 | 256通り | すべて成立 |
| 0とは元のまま | a⊕0 = a | 256通り | すべて成立 |
| 2回で元に戻る | (a⊕b)⊕b = a | 65,536通り | すべて成立 |
| 全部1とは反転 | a⊕11111111 = ¬a | 256通り | すべて成立 |
a と b は 0〜255 のすべて、結合法則の c は 0・1・85・170・255 の5つで確かめました(256×256×5=327,680通り)。数学の言葉では、XORを演算とするビット列の集まりは「どの要素も自分自身が逆元になる」群(アーベル群)になります。順番を入れ替えても、まとめ方を変えても結果が同じなので、大量の値をどんな順番でXORしても答えが変わりません。後の節の「重複していない1つを探す」は、この性質を使っています。
「2回で元に戻る」ことは、データの差分にも使えます。2つの同じ長さのバイト列をXORすると、違う位置だけが0以外になり、その差分をもう一度XORすると、もう一方に戻ります。
old = b'version=1;mode=A'
new = b'version=2;mode=B'
diff = bytes(x ^ y for x, y in zip(old, new))
print('差分', diff.hex())
print('old^差分', bytes(x ^ y for x, y in zip(old, diff)))
差分 00000000000000000300000000000003
old^差分 b'version=2;mode=B'
差分の 03 が2か所にだけ出ています('1' と '2'、'A' と 'B' がそれぞれ下位2ビットだけ違うため)。なお、この性質から「XORで暗号を作れる」と説明する記事もありますが、鍵の扱いを含めて安全な暗号を自作するのは難しく、暗号は専用のライブラリを使います。
プログラミング言語別のXORの書き方と実行結果
この節では、主な言語とSQL・表計算でのXORの書き方と、同じ計算を実行した結果の違いが分かります。
整数のXORは、ほとんどの言語で ^ と書きます。ただし、負の数・真偽値・小数・大きな数の扱いと、演算子の優先順位は言語ごとに違います。同じ式を8言語で実行した結果です。
| 言語 | 5 ^ 3 | -5 ^ 3 | 真偽値の XOR | 2 ^ 10 |
|---|---|---|---|---|
| Python 3.13 | 6 | -8 | True ^ False → True(bool) | 8 |
| JavaScript(Node.js 22) | 6 | -8 | true ^ false → 1(number) | 8 |
| Java 21 | 6 | -8 | true ^ false → true(boolean) | 8 |
| C(gcc 13) | 6 | -8 | true ^ false → 1(int) | 8(-Wall で警告) |
| PHP 8.3 | 6 | -8 | true xor true → false | 8 |
| Ruby 3.3 | 6 | -8 | true ^ true → false | 8 |
| Rust 1.97 | 6 | -8 | true ^ false → true | 8 |
| bash 5.2 | 6($((5 ^ 3))) | -8 | 真偽値の型は無い | 8 |
-5 ^ 3 が -8 になるのは、負の数を2の補数(ビットを反転して1を足した形)で表しているためです。-5 は …11111011、3 は …00000011 で、XORすると …11111000 = -8 です。どの言語でも同じ結果でした。C では gcc が result of '2^10' is 8; did you mean '1 << 10' (1024)? と警告しました(後の節で原文を載せます)。
Python
print('5 ^ 3 =', 5 ^ 3)
print('0xAB ^ 0x0F =', hex(0xAB ^ 0x0F))
print('True ^ False =', True ^ False, type(True ^ False).__name__)
print('2 ^ 10 =', 2 ^ 10, ' 2 ** 10 =', 2 ** 10)
a, b = 6, 6
print('a ^ b == 0 ->', a ^ b == 0)
print('bin:', format(0b1100 ^ 0b1010, '04b'))
print('operator.xor:', __import__('operator').xor(12, 10))
5 ^ 3 = 6
0xAB ^ 0x0F = 0xa4
True ^ False = True bool
2 ^ 10 = 8 2 ** 10 = 1024
a ^ b == 0 -> True
bin: 0110
operator.xor: 6
Python 言語リファレンスは、^ について「引数のビット単位の XOR(排他的論理和)」を返し、引数は整数(または __xor__() を定義したオブジェクト)でなければならない、と説明しています。また、比較演算は「C と違い」どのビット演算よりも優先順位が低いため、a ^ b == 0 は (a ^ b) == 0 と読まれます。
JavaScript
console.log('5 ^ 3 =', 5 ^ 3);
console.log('true ^ false =', true ^ false, typeof (true ^ false));
const a = 6, b = 6;
console.log('a ^ b == 0 ->', a ^ b == 0);
console.log('(a ^ b) == 0 ->', (a ^ b) == 0);
console.log('1.5 ^ 1 =', 1.5 ^ 1);
console.log('2**32 ^ 0 =', 2**32 ^ 0);
console.log('0xFFFFFFFF ^ 0 =', 0xFFFFFFFF ^ 0);
console.log('(0xFFFFFFFF ^ 0) >>> 0 =', (0xFFFFFFFF ^ 0) >>> 0);
console.log('2n**64n ^ 1n =', (2n**64n) ^ 1n);
try { 1n ^ 1 } catch (e) { console.log('1n ^ 1 ->', e.constructor.name + ':', e.message); }
5 ^ 3 = 6
true ^ false = 1 number
a ^ b == 0 -> 6
(a ^ b) == 0 -> true
1.5 ^ 1 = 0
2**32 ^ 0 = 0
0xFFFFFFFF ^ 0 = -1
(0xFFFFFFFF ^ 0) >>> 0 = 4294967295
2n**64n ^ 1n = 18446744073709551617n
1n ^ 1 -> TypeError: Cannot mix BigInt and other types, use explicit conversions
MDN によると、数値の ^ はオペランドを32ビット整数に変換してから計算し、32ビットを超える部分は捨てられます。1.5 が 1 に、2の32乗が 0 になったのはこのためです。BigInt どうしなら桁は切り捨てられず、BigInt と数値を混ぜると TypeError になります。
Java
public class X {
public static void main(String[] args) {
System.out.println("5 ^ 3 = " + (5 ^ 3));
boolean t = true, f = false;
System.out.println("true ^ false = " + (t ^ f));
System.out.println("2 ^ 10 = " + (2 ^ 10) + " Math.pow(2,10) = " + Math.pow(2, 10));
int a = 6, b = 6;
System.out.println("(a ^ b) == 0 -> " + ((a ^ b) == 0));
System.out.println("Boolean.logicalXor = " + Boolean.logicalXor(true, true));
}
}
5 ^ 3 = 6
true ^ false = true
2 ^ 10 = 8 Math.pow(2,10) = 1024.0
(a ^ b) == 0 -> true
Boolean.logicalXor = false
Java の ^ は、整数ならビットごとのXOR、boolean なら論理のXORです。Boolean.logicalXor(a, b) というメソッドもあり、意図を名前で示せます。Java の演算子と優先順位の一覧は関連記事「Java演算子一覧と優先順位表|三項演算子・インクリメントの注意点」で、ビット演算全体とシフトは関連記事「Javaビット演算入門|シフト演算>>と>>>の違いとフラグ管理」で扱っています。
C
#include <stdio.h>
#include <stdbool.h>
int main(void){
printf("5 ^ 3 = %d\n", 5 ^ 3);
printf("0xAB ^ 0x0F = 0x%X\n", 0xAB ^ 0x0F);
bool t = true, f = false;
printf("true ^ false = %d\n", t ^ f);
printf("!!2 != !!4 = %d (2 ^ 4 = %d)\n", !!2 != !!4, 2 ^ 4);
int a = 6, b = 6;
printf("a ^ b == 0 -> %d\n", a ^ b == 0);
printf("(a ^ b) == 0 -> %d\n", (a ^ b) == 0);
return 0;
}
5 ^ 3 = 6
0xAB ^ 0x0F = 0xA4
true ^ false = 1
!!2 != !!4 = 0 (2 ^ 4 = 6)
a ^ b == 0 -> 6
(a ^ b) == 0 -> 1
C には論理のXOR演算子(^^ のようなもの)がありません。0以外を真とする値どうしで「どちらか一方だけ真か」を調べるときは、!!a != !!b のように0か1にそろえてから比べます。2 と 4 はどちらも真なので論理のXORは0ですが、ビットのXOR 2 ^ 4 は6(真)になり、結果が逆になります。
PHP・Ruby・Rust・bash
<?php
echo "5 ^ 3 = ", 5 ^ 3, "\n";
echo "true xor true = "; var_dump(true xor true);
$r = true xor true; echo "\$r = true xor true -> "; var_dump($r);
$s = (true xor true); echo "\$s = (true xor true) -> "; var_dump($s);
5 ^ 3 = 6
true xor true = bool(false)
$r = true xor true -> bool(true)
$s = (true xor true) -> bool(false)
PHP の xor は論理のXORですが、代入の = より優先順位が低いため、$r = true xor true は ($r = true) xor true と読まれ、$r に true が入りました。PHP マニュアルの優先順位表でも、and・xor・or は代入演算子より下に並んでいます。括弧で囲むと期待どおり false です。
Ruby(5 ^ 3 → 6、true ^ true → false、2 ** 10 → 1024)、Rust(5 ^ 3 → 6、true ^ false → true、0b1100u8 ^ 0b1010 → 0110)、bash(echo $((5 ^ 3)) → 6、printf "%x\n" $((0xAB ^ 0x0F)) → a4)も、^ でXORになりました。
SQL(PostgreSQL・MySQL・SQLite)
SELECT 5 # 3 AS int_xor, 5 ^ 3 AS caret, B'1100' # B'1010' AS bit_xor;
SELECT true <> true AS bool_xor_tt, true <> false AS bool_xor_tf;
UPDATE flags SET f = f # 4 RETURNING id, f;
SELECT bit_xor(x) FROM (VALUES (3),(5),(3),(7),(5)) t(x);
SELECT true # false;
int_xor | caret | bit_xor
---------+-------+---------
6 | 125 | 0110
bool_xor_tt | bool_xor_tf
-------------+-------------
f | t
id | f
----+---
1 | 1
2 | 2
bit_xor
---------
7
ERROR: operator does not exist: boolean # boolean
LINE 1: SELECT true # false;
^
HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
PostgreSQL では ^ はべき乗で、5 ^ 3 は 125 になりました。整数とビット列のXORは # です。真偽値の XOR 演算子は無いため、<>(等しくない)で書きます。集約関数 bit_xor は、列の全行をXORします(3・5・3・7・5 の中で1回だけの7が残りました)。flags の f(5 と 6)は # 4 で4の位のビットだけが反転して 1 と 2 になっています。
MySQL は手元で動かしていませんが、MySQL 8.4 リファレンスマニュアルでは、XOR は論理のXORで「どちらかが NULL なら NULL」「NULL 以外では0以外のオペランドの数が奇数なら1」と説明され、SELECT 1 XOR 1 XOR 1 は 1 です。ビットのXORは ^ です。SQLite(3.53.1)には XOR の演算子が無く、次のエラーになりました。
SELECT 5 ^ 3 -> OperationalError: unrecognized token: "^"
SELECT 5 XOR 3 -> OperationalError: near "3": syntax error
SELECT (5 | 3) - (5 & 3) -> (6,)
SELECT (1=1) <> (1=0) -> (1,)
SQLite で整数のXORが要るときは (a | b) - (a & b)(ORからANDを引く)で計算できます。同じ ^ でも、Python・Java・C は XOR、PostgreSQL はべき乗、SQLite はエラーです。SQL を書くときは、使っている製品のマニュアルで演算子を確かめます。
Excel・スプレッドシート
Microsoft サポートの「XOR 関数」によると、書式は XOR(論理式 1, [論理式 2],…) で、論理式は1〜254個まで指定でき、TRUE と評価される入力の数が奇数なら TRUE を返します。指定した範囲に論理値が含まれていないと #VALUE! になります。対応は Excel 2016 以降と Microsoft 365 です。整数のビットごとのXORは BITXOR 関数で、手元の LibreOffice Calc では BITXOR(5,3) が 6 でした。
ブール値のXORと論理演算子の違い
この節では、真偽値(ブール値)をXORするときの書き方と、ビット演算の ^ と論理演算の違いが分かります。
真偽値どうしのXORは「等しくない(!=)」と同じ結果です。真理値表を見ると、XORは「違えば1」、!= も「違えば真」なので、4通りすべて一致します。言語によっては != のほうが意図が伝わりやすく、型も真偽値のまま返ります。
ビット演算の ^
整数の各ビットを1つずつXORする
5 ^ 3 = 101 ^ 011 = 110 = 6
短絡評価(途中で打ち切り)はしない
論理としてのXOR
真か偽かだけを見て「一方だけ真」を判定する
!=、Java の boolean ^、PHP の xor、MySQL の XOR
XORは両辺を見ないと決まらないので、短絡評価できない
AND(&&)や OR(||)は、左側だけで答えが決まれば右側を評価しません(短絡評価)。XORは左が真でも偽でも、右を見ないと答えが決まらないため、多くの言語に「&& や || のような論理のXOR演算子」がありません。そこで次のように書き分けます。
| 言語 | 真偽値のXORの書き方 | 結果の型(手元の実行) |
|---|---|---|
| Python | a != b、または a ^ b(bool どうし) | bool(True ^ False → True) |
| JavaScript | a !== b(両方 boolean のとき) | ^ だと number(1)になる |
| Java | a ^ b、a != b、Boolean.logicalXor(a, b) | boolean |
| C | !!a != !!b(0以外を真とする値) | int(0か1) |
| PHP | (a xor b)、a !== b | bool。xor は括弧で囲む |
| SQL | MySQL は a XOR b、PostgreSQL は a <> b | PostgreSQL は boolean(t・f) |
JavaScript や Python で、真偽値ではない値(空文字・0・None など)が混ざる場合は、Boolean(a) !== Boolean(b)、bool(a) != bool(b) のように真偽値にそろえてから比べます。Python で None ^ True と書くと TypeError: unsupported operand type(s) for ^: 'NoneType' and 'bool' になりました。
ビット演算でのXORの使い道(フラグ反転・入れ替え・パリティ)
この節では、プログラムでXORがよく使われる場面と、その実行結果が分かります。
XORは「決まったビットだけを反転する」「違いを取り出す」「1の個数の偶奇を求める」ときに使います。代表的な使い道を並べ、Python で実行した結果を載せます。
1フラグの反転(トグル)
x ^= マスク で、マスクの1のビットだけが反転し、ほかは変わらない。同じ操作をもう一度で元に戻る。
2パリティ(偶奇)
全ビットをXORすると、1の個数が奇数なら1。通信や記憶装置の誤り検出に使う。
3失った1つの復元
A⊕B⊕C をパリティとして持てば、どれか1つを失っても残りとパリティのXORで戻せる。RAID 5 の考え方。
4違いの検出
a ^ b が0なら同じ、0以外なら1のビットが違う位置。(a ^ b) < 0 なら符号が違う。
フラグの反転
READ, WRITE, EXEC = 1, 2, 4
p = READ | EXEC
print(f'初期 {p:03b}')
p ^= WRITE; print(f'WRITEを反転 {p:03b}')
p ^= WRITE; print(f'もう一度反転 {p:03b}')
p ^= READ | EXEC; print(f'READとEXECを同時に反転 {p:03b}')
初期 101
WRITEを反転 111
もう一度反転 101
READとEXECを同時に反転 000
ビットを「立てる」なら | 、「下ろす」なら & ~、「反転する」なら ^ と使い分けます。画面の表示・非表示を切り替えるボタンのように、今の状態に関係なく反対にしたいときが ^ の出番です。ただし、ボタンを2回押したときの「2回目」が必ず届く保証が無い場面(通信の再送など)では、反転より「この値にする」と書くほうが安全です。
パリティ
00001011 1の数 3 パリティ 1 bit_count%2 1
00001001 1の数 2 パリティ 0 bit_count%2 0
11111111 1の数 8 パリティ 0 bit_count%2 0
10000000 1の数 1 パリティ 1 bit_count%2 1
1ビットずつXORした結果と、Python 3.10 以降の int.bit_count()(1の個数)を2で割った余りが一致しました。パリティは1ビットの誤りなら見つけられますが、2ビット同時の誤りは見逃します。
1ブロックの復元(RAID 5 の考え方)とXORチェックサムの弱点
d1, d2, d3 = b'ABCD', b'EFGH', b'IJKL'
par = bytes(a ^ b ^ c for a, b, c in zip(d1, d2, d3))
print('パリティ', par.hex())
print('d2を失った → d1^d3^パリティ =', bytes(a ^ b ^ c for a, b, c in zip(d1, d3, par)))
cs = lambda b: functools.reduce(operator.xor, b, 0)
print('ABCD', hex(cs(b'ABCD')), ' DCBA', hex(cs(b'DCBA')), ' ABCE', hex(cs(b'ABCE')))
パリティ 4d4e4f40
d2を失った → d1^d3^パリティ = b'EFGH'
ABCD 0x4 DCBA 0x4 ABCE 0x5
失った d2 が、残りのデータとパリティのXORで元どおりになりました。一方、全バイトをXORしただけのチェックサムは、1文字の変化(ABCD→ABCE)は見つけられますが、順番の入れ替え(ABCD→DCBA)は同じ値になり見逃します。交換法則が成り立つためです。ファイルの改ざんや破損を確かめる用途には、CRC や SHA-256 などのハッシュを使います。
値の入れ替え(XORスワップ)
一時変数を使わずに2つの値を入れ替える書き方として、XORスワップがよく紹介されます。手元で確かめると、今のコンピューターでは得になる場面がほとんどありませんでした。
gcc 13.3.0 で -O2 を付けてアセンブリを出すと、一時変数を使う関数は読み込み2回・書き込み2回の4命令、XORスワップは xorl を3回含む6命令になりました。さらに、同じ場所を指す2つのポインターでXORスワップすると、値が0に消えます。
void swap(int *x, int *y){ *x ^= *y; *y ^= *x; *x ^= *y; }
/* ... */
int p = 3, q = 9; swap(&p, &q); printf("swap(3,9) -> %d %d\n", p, q);
int r = 7; swap(&r, &r); printf("swap(&r,&r) r=7 -> %d\n", r);
swap(3,9) -> 9 3
swap(&r,&r) r=7 -> 0
最初の *x ^= *y で、同じ場所の値が自分自身とのXORになり0になるためです。配列の並べ替えで i と j が同じになる場合などに起こります。入れ替えは、言語の普通の書き方(Python の a, b = b, a、C の一時変数、C++ の std::swap)で書きます。
XORで重複していない1つを探す(実測)
この節では、プログラミングの練習問題で有名な「1つだけ重複していない数を探す」問題をXORで解く方法と、ほかの解き方との速さ・メモリの比較が分かります。
「1つの値を除き、ほかはすべてちょうど2回ずつ出てくる配列」なら、全部をXORした結果が答えです。同じ値どうしは0になって消え、順番も関係ないためです。追加のメモリはほぼ要りません。
def by_xor(a):
x = 0
for v in a:
x ^= v
return x
# 同じ意味を1行で
import functools, operator
functools.reduce(operator.xor, a, 0)
手元の Python 3.13 で、10億未満の整数を使って配列を作り、XOR・Counter(出現回数を数える)・set(出たら入れ、2回目で消す)・並べ替え、の4通りで解きました。時間は5回の中央値、メモリは tracemalloc で測った追加分の最大です(2CPU のマシンを複数人で使っているため、時間は目安です)。
| 解き方 | 10万1個:時間 | 10万1個:メモリ | 100万1個:時間 | 100万1個:メモリ |
|---|---|---|---|---|
| XOR(for 文) | 6.0 ms | 0.00 MB | 82.7 ms | 0.00 MB |
| XOR(reduce) | 4.8 ms | 0.00 MB | 74.4 ms | 0.00 MB |
| Counter | 16.9 ms | 3.75 MB | 467.2 ms | 30.00 MB |
| set | 11.4 ms | 2.50 MB | 976.0 ms | 16.00 MB |
| 並べ替え | 20.9 ms | 1.14 MB | 1031.9 ms | 11.44 MB |
100万1個では、XORが Counter の約6分の1、set・並べ替えの約12分の1の時間で、追加のメモリは0でした。ただし、XORで解けるのは「ほかはちょうど偶数回」という前提が守られているときだけです。前提が崩れると、エラーにならずに違う答えを返します。
3回出る値がある [4,4,4,7,7] -> 4 (4 が奇数回なので残る)
1回の値が2つ [1,2,3,3] -> 3 (1^2 が混ざった値で、どちらでもない)
同じ考え方で「0〜n から1つだけ欠けた数」も求まります。0〜9 と、6 が欠けた配列を全部XORすると、6 だけが1回しか出てこないので 6 が残りました。入力の前提が確かでないデータ(ログや利用者の入力)では、Counter で回数を数えるほうが誤りに気づけます。
グレイコードとXOR
この節では、隣の数との違いが1ビットだけになる「グレイコード」をXORで作る方法と、元に戻す方法が分かります。
2進数 n のグレイコードは n ^ (n >> 1) で求まります。1つ右にずらした自分自身とXORするだけです。0〜7 を変換した結果です。
for n in range(8):
g = n ^ (n >> 1)
back, t = 0, g
while t:
back ^= t
t >>= 1
print(f'{n} {n:03b} -> {g:03b} 戻す {back}')
0 000 -> 000 戻す 0
1 001 -> 001 戻す 1
2 010 -> 011 戻す 2
3 011 -> 010 戻す 3
4 100 -> 110 戻す 4
5 101 -> 111 戻す 5
6 110 -> 101 戻す 6
7 111 -> 100 戻す 7
普通の2進数では 3(011)から 4(100)に進むとき3ビットが同時に変わりますが、グレイコードでは 010 から 110 で1ビットしか変わりません。回転の角度を読み取るセンサー(ロータリーエンコーダー)では、ビットが同時に変わる瞬間に読み取ると途中の値を拾ってしまうため、グレイコードが使われます。戻すときは、グレイコードを1ビットずつ右にずらしながら全部XORします。
XORのよくある間違い(^はべき乗ではない・優先順位)
この節では、XORを書くときに起きやすい誤りと、手元で出たエラー・警告の原文、直し方が分かります。
いちばん多いのは、^ をべき乗(累乗)だと思って書く誤りです。数学や Excel の数式では 2^10 が1024ですが、Python・Java・C・JavaScript などでは XOR なので 8 になります。エラーにならないため気づきにくく、gcc は次の警告で教えてくれました。
x.c:10:59: warning: result of '2^4' is 6; did you mean '1 << 4' (16)? [-Wxor-used-as-pow]
10 | printf("!!2 != !!4 = %d (2 ^ 4 = %d)\n", !!2 != !!4, 2 ^ 4);
| ^
| -
| 1 <<
x.c:10:57: note: you can silence this warning by using a hexadecimal constant (0x2 rather than 2)
次に多いのが優先順位です。C・Java・JavaScript では ^ が == より低いため、a ^ b == 0 は a ^ (b == 0) と読まれます。Python は逆で、比較がビット演算より低いので (a ^ b) == 0 と読まれます。同じ式でも言語で意味が変わるので、XORを比較と組み合わせるときは必ず括弧を付けます。
Bad.java:4: error: bad operand types for binary operator '^'
if (a ^ b == 0) System.out.println("same");
^
first type: int
second type: boolean
1 error
Java は int と boolean の XOR を許さないためコンパイルエラーで気づけますが、C は警告(suggest parentheses around comparison in operand of '^' [-Wparentheses]、-Wall のとき)だけで動き、JavaScript は何も言わずに 6 を返しました。
| 書いたもの | 言語 | 出たもの(原文) | 直し方 |
|---|---|---|---|
| 2 ^ 10 でべき乗のつもり | Python・Java・JS・C | 8(エラーなし)。C は warning: result of '2^4' is 6 | 2 ** 10、Math.pow(2, 10)、1 << 10 |
| a ^ b == 0 | Java | error: bad operand types for binary operator '^' | (a ^ b) == 0 |
| a ^ b == 0 | JavaScript・C | 6(a ^ (b == 0) と読まれる) | (a ^ b) == 0 |
| 1.5 ^ 1 | Python | TypeError: unsupported operand type(s) for ^: 'float' and 'int' | 整数に直してから計算する |
| d ^ 1(double) | C・Java | error: invalid operands to binary ^ (have 'double' and 'int') | 整数型で計算する |
| 1n ^ 1 | JavaScript | TypeError: Cannot mix BigInt and other types, use explicit conversions | 1n ^ 1n か、Number にそろえる |
| SELECT 5 ^ 3 | SQLite・PostgreSQL | SQLite は unrecognized token: "^"、PostgreSQL は 125 | PostgreSQL は #、SQLite は (a | b) - (a & b) |
| $r = true xor true | PHP | bool(true)(代入が先に行われる) | $r = (true xor true) |
JavaScript では、エラーにならずに値が変わる例もあります。1.5 ^ 1 は 0、2**32 ^ 0 は 0、0xFFFFFFFF ^ 0 は -1 でした。32ビットの符号付き整数に変換されるためで、符号なしの値として扱いたいときは >>> 0 を付けると 4294967295 になります。32ビットを超える値は BigInt で計算します。
べき乗を書くとき
x ^ 2 と書く。エラーにならず、違う値になるx ** 2、Java は Math.pow(x, 2)、C は pow(x, 2) か x * x^ が べき乗になるのは Excel の数式や PostgreSQL など一部だけ
- 1^ をべき乗のつもりで書いていないか2 ^ 10 が 8 になる。C は -Wall で警告が出る
- 2比較と混ぜるときに括弧を付けたかC・Java・JS は ^ が == より低い。Python は逆
- 3型は整数か小数は Python・Java・C でエラー。JS は黙って切り捨てる
- 4負の数・桁あふれを考えたか2の補数で計算される。JS は32ビットに切られる
- 5SQL は製品の演算子を確かめたかPostgreSQL の ^ はべき乗、XOR は #
XORを使うか決める判断表
この節では、やりたいことごとに、XORを使うのが向くか、別の書き方が向くかが分かります。
XORは「ビットを反転する」「違いを取り出す」「偶奇を求める」ときに向き、読みやすさや安全性が大事な場面では別の書き方が向きます。
| やりたいこと | XORを使う? | おすすめの書き方 | 理由 |
|---|---|---|---|
| 決まったビットだけ反転 | 使う | flags ^= MASK | ほかのビットに影響しない |
| 真偽値が「一方だけ真」か | どちらでも | a != b(言語により a ^ b) | != のほうが読み手に伝わりやすい |
| 2つの値の入れ替え | 使わない | a, b = b, a・一時変数・std::swap | 速くならず、同じ場所で0になる |
| 1つだけ奇数回の値を探す | 前提が確かなら使う | reduce(xor, a, 0) | 速くメモリが要らない。前提が崩れると黙って誤る |
| 誤り検出(簡易) | 1ビットの誤りなら使う | パリティビット | 入れ替えや2ビットの誤りは見逃す |
| ファイルの破損・改ざん検出 | 使わない | CRC・SHA-256 | XORの和は順番の入れ替えを見逃す |
| データの秘匿 | 使わない | 専用の暗号ライブラリ | 暗号の自作は危険 |
| べき乗 | 使わない | **・Math.pow・pow | ^ はべき乗ではない |
覚える順番は次のとおりです。上から順に、使う場面が多いものです。
- 1真理値表(違えば1)ORとの違いは「両方1のとき」だけ
- 2^ はべき乗ではないべき乗は ** か pow
- 3括弧を付ける比較との優先順位は言語で逆
- 4同じ値で2回XORすると元に戻るa⊕a=0、a⊕0=a から説明できる
- 5フラグ反転・パリティ^= マスク、全部XORで偶奇
- 6重複していない1つ・グレイコード練習問題やアルゴリズムで出る
XORの練習問題
この節では、ここまでの内容を確かめる練習問題と、その答え・考え方が分かります。答えは手元の Python で確かめた値です。
問1. 1 ⊕ 0 ⊕ 1 ⊕ 1 はいくつですか。
答え:1。1が3個(奇数)なので1です。
問2. 12 ^ 10 を2進数と10進数で答えてください。
答え:1100 ^ 1010 = 0110 = 6。Python の operator.xor(12, 10) も 6 でした。
問3. x の下から3ビット目(4の位)だけを反転する式を書いてください。
答え:x ^= 4(x ^= 1 << 2)。PostgreSQL なら f # 4 で、5 が 1、6 が 2 になりました。
問4. [3, 5, 3, 7, 5] の中で1回だけ出てくる値を、XORで求めてください。
答え:7。3⊕5⊕3⊕7⊕5 は、順番を入れ替えて (3⊕3)⊕(5⊕5)⊕7 = 0⊕0⊕7 = 7。PostgreSQL の bit_xor も 7 でした。
問5. Java で if (a ^ b == 0) がコンパイルエラーになる理由は何ですか。
答え:^ が == より優先順位が低く、a ^ (b == 0)(int と boolean のXOR)と読まれるためです。(a ^ b) == 0 と書きます。
問6. 5(101)のグレイコードは何ですか。
答え:101 ^ 010 = 111。5 ^ (5 >> 1) で 7 です。
問7. 3つの入力 A・B・C のうち「ちょうど1つだけ真」を A⊕B⊕C で判定できますか。
答え:できません。3つとも真でも結果が真になります。真の個数を数えて1と比べます。
よくある質問
この節では、XOR・排他的論理和について検索でよく調べられる疑問への答えが分かります。
Q. XORと排他的論理和は同じものですか? A. 同じです。XOR は英語の eXclusive OR の略で、日本語訳が排他的論理和です。EOR・EX-OR と書く資料もあります。
Q. XORはどう読みますか? A. 「エックスオア」と読むのが一般的です。「エクスクルーシブオア」と読むこともあります。
Q. ⊕ の記号はどう入力しますか? A. Unicode では U+2295(CIRCLED PLUS)です。論理学の ⊻ は U+22BB(XOR)という名前の文字です。文書やコードのコメントでは、^ や XOR と書くほうが伝わりやすい場面もあります。
Q. XORとORの違いを一言で言うと? A. 両方が真のときの結果だけが違います。ORは真、XORは偽です。
Q. XNORとは何ですか? A. XORの結果を反転したもので、2つが同じとき1になります。「一致」の判定と同じです。
Q. Pythonで2^3が8にならないのはなぜですか?
A. Python の ^ はXORで、2 ^ 3 は 010 ^ 011 = 001 = 1 になります。べき乗は 2 ** 3 か pow(2, 3) と書きます。
Q. Excelで「XOR」はどう書きますか?
A. 真偽値は =XOR(A1>0, B1>0) のように XOR 関数、整数のビットごとのXORは BITXOR 関数です。Excel の数式の ^ はべき乗です。
Q. XORは基本情報技術者試験に出ますか? A. 論理演算の真理値表・ベン図・論理回路の問題として、ITパスポート試験や基本情報技術者試験などで扱われる範囲です。この記事の真理値表、3入力の決まり、半加算器を押さえておくと解きやすくなります。
Q. XORで暗号は作れますか? A. 2回で元に戻る性質は暗号の部品にも使われますが、安全な暗号を自作するのは難しいため、暗号は専用のライブラリを使います。
Q. 文字列どうしをXORできますか?
A. Python では TypeError: unsupported operand type(s) for ^: 'str' and 'str' になり、JavaScript では数値に変換されて "a" ^ "b" が 0 になりました。PHP は文字列の各バイトをXORします("a" ^ "b" は 0x03)。バイト列にしてから1バイトずつXORするのが確実です。
まとめ
- XOR(排他的論理和)は、入力が違うときだけ1になる演算。ORとの違いは両方1のときだけで、3つ以上なら「1の個数が奇数なら1」。
- 同じ値で2回XORすると元に戻る。a⊕a=0・a⊕0=a・交換法則・結合法則を8ビットの全組み合わせで確かめた。
- 多くの言語で ^ はXORで、べき乗ではない。PostgreSQL では ^ がべき乗でXORは #、SQLite には演算子が無い。
- 比較と組み合わせるときは括弧を付ける。C・Java・JS は a ^ b == 0 を a ^ (b == 0) と読み、Python は (a ^ b) == 0 と読む。
- 使い道はフラグ反転・パリティ・差分・重複していない1つを探す・グレイコード。入れ替え・改ざん検出・暗号には使わない。
参考・出典
確認日はいずれも 2026年10月29日です。
- Microsoft サポート「XOR 関数」:https://support.microsoft.com/ja-jp/office/xor-関数-1548d4c2-5e47-4f77-9a92-0533bba14f37
- MySQL 8.4 Reference Manual「14.4.3 Logical Operators」:https://dev.mysql.com/doc/refman/8.4/en/logical-operators.html
- Python 言語リファレンス「6. 式 (expression)」6.9 Binary bitwise operations・6.10 Comparisons:https://docs.python.org/3/reference/expressions.html
- MDN「ビット排他的論理和 (^)」:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Bitwise_XOR
- Oracle「The Java Language Specification, Java SE 21 Edition」15.22 Bitwise and Logical Operators:https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.22
- PHP マニュアル「演算子の優先順位」:https://www.php.net/manual/ja/language.operators.precedence.php
- PostgreSQL Documentation「Mathematical Functions and Operators」:https://www.postgresql.org/docs/current/functions-math.html
- PostgreSQL Documentation「Aggregate Functions」:https://www.postgresql.org/docs/current/functions-aggregate.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「XORとは?排他的論理和の真理値表と使い道|8言語とSQLで実行」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。