本記事では、PythonでのXOR(排他的論理和)について解説します。XORはプログラミングにおいて重要な論理演算子であり、データ処理や暗号化など様々な場面で活用されています。
XOR(排他的論理和)とは
XOR(排他的論理和)は、2つの入力のうち、どちらか一方だけが真(True)の場合に真(True)を返す論理演算です。両方が真または両方が偽の場合は偽(False)を返します。
XORの真理値表は以下のようになります。
A | B | A XOR B |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
この特性により、XORは様々なアルゴリズムやデータ処理で重要な役割を果たします。
構文
Pythonでは、XOR演算子として「^」(キャレット)を使用します。この演算子は主に以下の2つの方法で使われます。
- ビット単位のXOR演算
- 論理XOR演算
ビット単位のXOR演算
ビット単位のXOR演算は、2つの整数のビット表現を比較し、対応するビットが異なる場合に1、同じ場合に0を返します。
a = 5 # 二進数: 101
b = 3 # 二進数: 011
result = a ^ b # 二進数: 110 (十進数: 6)
print(f"5 ^ 3 = {result}")
# 出力: 5 ^ 3 = 6
論理XOR演算
Pythonには論理XOR演算子が直接用意されていませんが、比較演算子を使って同様の機能を実現できます。
a = True
b = False
result = (a or b) and not (a and b) # True XOR False
print(f"True XOR False = {result}")
# 出力: True XOR False = True
または、ビット演算子^を使って論理XOR演算を行うこともできます。
a = True
b = False
result = a ^ b
print(f"True ^ False = {result}")
# 出力: True ^ False = True
operatorモジュールを使用したXOR演算
Pythonの標準ライブラリであるoperator
モジュールには、XOR演算を行うためのxor
関数が用意されています。この関数を使用することで、より明示的にXOR演算を行うことができます。
import operator
# 整数のXOR演算
a = 5
b = 3
result = operator.xor(a, b)
print(f"operator.xor(5, 3) = {result}")
# 論理値のXOR演算
c = True
d = False
logic_result = operator.xor(c, d)
print(f"operator.xor(True, False) = {logic_result}")
# 出力:
# operator.xor(5, 3) = 6
# operator.xor(True, False) = True
operator
モジュールのxor
関数は、ビット演算子^
と同じ動作をしますが、関数形式で使用できるため、高階関数(map
やreduce
など)と組み合わせる場合に便利です。
例
例1: 数値のビット反転
XOR演算を使って特定のビットを反転させる例です。
# 特定のビットを反転させる
num = 10 # 二進数: 1010
mask = 12 # 二進数: 1100
result = num ^ mask # 二進数: 0110 (十進数: 6)
print(f"10 ^ 12 = {result}")
# 出力: 10 ^ 12 = 6
例2: 簡易的な暗号化
XOR演算を使った簡易的な暗号化の例です。同じキーでXOR演算を2回行うと元の値に戻るという性質を利用しています。
# XORを使った簡易暗号化
def xor_encrypt(data, key):
# 各バイトをキーとXOR演算
encrypted = bytes([b ^ key for b in data])
return encrypted
# 元のデータ
message = b"Hello, Python!"
key = 42
# 暗号化
encrypted = xor_encrypt(message, key)
print(f"暗号化: {encrypted}")
# 復号化(同じキーでXOR演算)
decrypted = xor_encrypt(encrypted, key)
print(f"復号化: {decrypted}")
print(f"復号化テキスト: {decrypted.decode('utf-8')}")
# 出力:
# 暗号化: b'j\x17\x1a\x1a\x13\x0c(h\x03\x06\x18\x13\x12\x7f'
# 復号化: b'Hello, Python!'
# 復号化テキスト: Hello, Python!
例3: 重複する要素の検出
XOR演算を使って配列内の重複しない要素を見つける例です。
# 配列内で1つだけ存在する要素を見つける
def find_single_element(arr):
result = 0
for num in arr:
result ^= num
return result
# 全ての要素が2回ずつ出現し、1つだけが1回だけ出現する配列
nums = [4, 1, 2, 1, 2]
single = find_single_element(nums)
print(f"配列 {nums} で1回だけ出現する要素: {single}")
# 出力: 配列 [4, 1, 2, 1, 2] で1回だけ出現する要素: 4
注意点
1. ビット演算と論理演算の違い
XOR演算子(^)はビット演算子であり、論理演算子ではないことに注意が必要です。論理演算としてXORを使用する場合は、明示的に論理値(True/False)に変換するか、論理演算の組み合わせを使用しましょう。
# ビット演算と論理演算の違い
a = 5
b = 3
# ビット演算
bit_result = a ^ b
print(f"ビット演算 5 ^ 3 = {bit_result}")
# 論理演算(間違った使い方)
logic_result_wrong = a ^ b != 0 # 誤解を招く可能性がある
print(f"論理演算(誤): {logic_result_wrong}")
# 論理演算(正しい使い方)
logic_result_correct = bool(a) ^ bool(b)
print(f"論理演算(正): {logic_result_correct}")
# 出力:
# ビット演算 5 ^ 3 = 6
# 論理演算(誤): True
# 論理演算(正): False
2. 優先順位
XOR演算子(^)の優先順位は、他の演算子と比較して低いことに注意が必要です。複雑な式では括弧を使用して明示的に順序を指定することをお勧めします。
# 演算子の優先順位
a = 5
b = 3
c = 2
# 括弧なし
result1 = a ^ b * c
print(f"a ^ b * c = {result1}") # b * c が先に計算される
# 括弧あり
result2 = (a ^ b) * c
print(f"(a ^ b) * c = {result2}") # a ^ b が先に計算される
# 出力:
# a ^ b * c = 1
# (a ^ b) * c = 12
3. 浮動小数点数との使用
XOR演算子(^)は整数型に対してのみ使用できます。浮動小数点数に対して使用すると、TypeError例外が発生します。
# 浮動小数点数との使用(エラーになる例)
try:
result = 5.0 ^ 3.0
print(result)
except TypeError as e:
print(f"エラー: {e}")
# 出力: エラー: unsupported operand type(s) for ^: 'float' and 'float'
まとめ
PythonでのXOR演算は、ビット操作や論理演算において非常に便利なツールです。主な特徴と用途をまとめると:
- XORは「排他的論理和」を意味し、2つの入力のうち1つだけが真の場合に真を返す
- Pythonでは「^」演算子を使用してXOR演算を行う
- ビット単位の操作や、値の交換、簡易暗号化、重複要素の検出など様々な用途がある
- 使用する際は、ビット演算と論理演算の違い、演算子の優先順位、データ型の制約に注意する
XOR演算の特性を理解し活用することで、より効率的なコードを書くことができます。特にビット操作が必要なアルゴリズムや、暗号化処理などで威力を発揮するでしょう。