Pythonビット演算子完全ガイド – &・|・^・~・<<・>>の使い方と活用法

 

ビット演算子とは?

Python のビット演算子は、数値をバイナリ(2進数)レベルで操作するための演算子です。整数の各ビットに対して論理演算やシフト操作を行い、高速な計算やフラグ管理、暗号化処理などで威力を発揮します。

基本的なビット演算子一覧

1. AND演算子(&)

両方のビットが1の場合のみ1を返します。

# 基本的なAND演算
a = 12  # 1100 (2進数)
b = 8   # 1000 (2進数)
result = a & b  # 1000 = 8
print(f"{a} & {b} = {result}")  # 12 & 8 = 8

# バイナリ表示で確認
print(f"{bin(a)} & {bin(b)} = {bin(result)}")
# 0b1100 & 0b1000 = 0b1000

2. OR演算子(|)

どちらかのビットが1の場合に1を返します。

# 基本的なOR演算
a = 12  # 1100 (2進数)
b = 8   # 1000 (2進数)
result = a | b  # 1100 = 12
print(f"{a} | {b} = {result}")  # 12 | 8 = 12

# より明確な例
x = 5   # 0101
y = 3   # 0011
result = x | y  # 0111 = 7
print(f"{x} | {y} = {result}")  # 5 | 3 = 7

3. XOR演算子(^)

ビットが異なる場合のみ1を返します。

# 基本的なXOR演算
a = 12  # 1100
b = 8   # 1000
result = a ^ b  # 0100 = 4
print(f"{a} ^ {b} = {result}")  # 12 ^ 8 = 4

# XORの特性:同じ数でXORすると0
x = 42
result = x ^ x
print(f"{x} ^ {x} = {result}")  # 42 ^ 42 = 0

4. NOT演算子(~)

すべてのビットを反転させます。

# 基本的なNOT演算
a = 5   # 0101
result = ~a  # ...11111010 = -6
print(f"~{a} = {result}")  # ~5 = -6

# 8ビットでの例
b = 255  # 11111111
result = ~b  # -256
print(f"~{b} = {result}")  # ~255 = -256

5. 左シフト演算子(<<)

ビットを左にシフト(2のn乗倍)します。

# 基本的な左シフト
a = 5    # 0101
result = a << 1  # 1010 = 10
print(f"{a} << 1 = {result}")  # 5 << 1 = 10

# 複数ビットシフト
result = a << 2  # 10100 = 20
print(f"{a} << 2 = {result}")  # 5 << 2 = 20

# 2のn乗計算
power = 2 ** 3
shift = 1 << 3
print(f"2^3 = {power}, 1<<3 = {shift}")  # 2^3 = 8, 1<<3 = 8

6. 右シフト演算子(>>)

ビットを右にシフト(2のn乗で割る)します。

# 基本的な右シフト
a = 20   # 10100
result = a >> 1  # 01010 = 10
print(f"{a} >> 1 = {result}")  # 20 >> 1 = 10

# 複数ビットシフト
result = a >> 2  # 00101 = 5
print(f"{a} >> 2 = {result}")  # 20 >> 2 = 5

# 整数除算との比較
div_result = 20 // 4
shift_result = 20 >> 2
print(f"20//4 = {div_result}, 20>>2 = {shift_result}")  # 両方とも5

ビット演算の実践的な応用

1. フラグ管理システム

# 権限フラグの定義
READ = 1    # 0001
WRITE = 2   # 0010
EXECUTE = 4 # 0100
DELETE = 8  # 1000

def set_permission(current, permission):
    return current | permission

def remove_permission(current, permission):
    return current & ~permission

def has_permission(current, permission):
    return (current & permission) == permission

# 使用例
permissions = 0  # 初期状態
permissions = set_permission(permissions, READ | WRITE)
print(f"読み取り権限あり: {has_permission(permissions, READ)}")  # True
print(f"削除権限あり: {has_permission(permissions, DELETE)}")    # False

2. 高速な偶数・奇数判定

def is_even_fast(n):
    return (n & 1) == 0

def is_odd_fast(n):
    return (n & 1) == 1

# 使用例
numbers = [10, 15, 22, 33, 44]
for num in numbers:
    result = "偶数" if is_even_fast(num) else "奇数"
    print(f"{num}は{result}")

3. 2の累乗判定

def is_power_of_two(n):
    return n > 0 and (n & (n - 1)) == 0

# 使用例
test_numbers = [1, 2, 4, 6, 8, 15, 16, 32]
for num in test_numbers:
    result = is_power_of_two(num)
    print(f"{num}は2の累乗: {result}")

暗号化・セキュリティでの活用

1. 簡単なXOR暗号化

def xor_encrypt(text, key):
    return ''.join(chr(ord(char) ^ key) for char in text)

def xor_decrypt(encrypted, key):
    return xor_encrypt(encrypted, key)  # XORは可逆

# 使用例
message = "Hello World"
key = 123
encrypted = xor_encrypt(message, key)
decrypted = xor_decrypt(encrypted, key)

print(f"元のメッセージ: {message}")
print(f"暗号化: {encrypted}")
print(f"復号化: {decrypted}")

2. ハッシュ関数での活用

def simple_hash(text):
    hash_value = 0
    for char in text:
        hash_value = (hash_value << 5) ^ ord(char)
        hash_value &= 0xFFFFFFFF  # 32ビット制限
    return hash_value

# 使用例
strings = ["apple", "banana", "cherry"]
for s in strings:
    hash_val = simple_hash(s)
    print(f"'{s}' のハッシュ値: {hash_val}")

パフォーマンス最適化

1. 高速な乗算・除算

import timeit

def multiply_by_power_of_two(n, power):
    return n << power

def divide_by_power_of_two(n, power):
    return n >> power

# パフォーマンス比較
n = 1000
# 通常の計算
time1 = timeit.timeit(lambda: n * 8, number=1000000)
# ビットシフト
time2 = timeit.timeit(lambda: n << 3, number=1000000)

print(f"通常の乗算: {time1:.6f}秒")
print(f"ビットシフト: {time2:.6f}秒")

2. 配列インデックスの最適化

def next_power_of_two(n):
    if n <= 1:
        return 1
    n -= 1
    n |= n >> 1
    n |= n >> 2
    n |= n >> 4
    n |= n >> 8
    n |= n >> 16
    return n + 1

# 使用例
test_values = [3, 7, 15, 20, 100]
for val in test_values:
    result = next_power_of_two(val)
    print(f"{val} → {result}")

ビットマスクの活用

1. 状態管理システム

class TaskStatus:
    PENDING = 1     # 0001
    RUNNING = 2     # 0010
    COMPLETED = 4   # 0100
    FAILED = 8      # 1000

class Task:
    def __init__(self):
        self.status = 0
    
    def add_status(self, status):
        self.status |= status
    
    def remove_status(self, status):
        self.status &= ~status
    
    def has_status(self, status):
        return (self.status & status) != 0
    
    def get_status_list(self):
        statuses = []
        if self.has_status(TaskStatus.PENDING):
            statuses.append("PENDING")
        if self.has_status(TaskStatus.RUNNING):
            statuses.append("RUNNING")
        if self.has_status(TaskStatus.COMPLETED):
            statuses.append("COMPLETED")
        if self.has_status(TaskStatus.FAILED):
            statuses.append("FAILED")
        return statuses

# 使用例
task = Task()
task.add_status(TaskStatus.PENDING | TaskStatus.RUNNING)
print(f"現在の状態: {task.get_status_list()}")

2. RGB色の操作

def rgb_to_int(r, g, b):
    return (r << 16) | (g << 8) | b

def int_to_rgb(color):
    r = (color >> 16) & 0xFF
    g = (color >> 8) & 0xFF
    b = color & 0xFF
    return r, g, b

def adjust_brightness(color, factor):
    r, g, b = int_to_rgb(color)
    r = min(255, int(r * factor))
    g = min(255, int(g * factor))
    b = min(255, int(b * factor))
    return rgb_to_int(r, g, b)

# 使用例
red = rgb_to_int(255, 0, 0)
print(f"赤色の整数値: {red}")
print(f"RGB分解: {int_to_rgb(red)}")

darker_red = adjust_brightness(red, 0.5)
print(f"暗い赤: {int_to_rgb(darker_red)}")

データ構造での活用

1. ビットセット(集合の表現)

class BitSet:
    def __init__(self, size=32):
        self.bits = 0
        self.size = size
    
    def add(self, element):
        if 0 <= element < self.size:
            self.bits |= (1 << element)
    
    def remove(self, element):
        if 0 <= element < self.size:
            self.bits &= ~(1 << element)
    
    def contains(self, element):
        if 0 <= element < self.size:
            return (self.bits & (1 << element)) != 0
        return False
    
    def to_list(self):
        return [i for i in range(self.size) if self.contains(i)]

# 使用例
bit_set = BitSet(10)
bit_set.add(1)
bit_set.add(3)
bit_set.add(7)
print(f"セットの要素: {bit_set.to_list()}")  # [1, 3, 7]

2. ブルームフィルタの基礎

class SimpleBloomFilter:
    def __init__(self, size=1000):
        self.size = size
        self.bit_array = 0
    
    def _hash1(self, item):
        return hash(item) % self.size
    
    def _hash2(self, item):
        return (hash(item) * 17) % self.size
    
    def add(self, item):
        h1 = self._hash1(item)
        h2 = self._hash2(item)
        self.bit_array |= (1 << h1)
        self.bit_array |= (1 << h2)
    
    def might_contain(self, item):
        h1 = self._hash1(item)
        h2 = self._hash2(item)
        return (self.bit_array & (1 << h1)) and (self.bit_array & (1 << h2))

# 使用例
bloom = SimpleBloomFilter(100)
bloom.add("apple")
bloom.add("banana")
print(f"'apple'が含まれる可能性: {bloom.might_contain('apple')}")
print(f"'orange'が含まれる可能性: {bloom.might_contain('orange')}")

よくある間違いと対処法

1. 負数での右シフト

# 負数の右シフトに注意
positive = 8
negative = -8

print(f"正数: {positive} >> 1 = {positive >> 1}")  # 4
print(f"負数: {negative} >> 1 = {negative >> 1}")  # -4

# 符号なしシフトが必要な場合
def unsigned_right_shift(n, bits):
    return (n % (1 << 32)) >> bits

print(f"符号なしシフト: {unsigned_right_shift(-8, 1)}")

2. ビット演算子と論理演算子の混同

# 間違い:論理演算子を使用
a, b = 5, 3
# wrong = a and b  # これは論理演算

# 正しい:ビット演算子を使用
correct = a & b
print(f"{a} & {b} = {correct}")  # 5 & 3 = 1

# ブール値での違い
bool1, bool2 = True, False
logical_and = bool1 and bool2  # False
bitwise_and = bool1 & bool2    # False (この場合は同じ)
print(f"論理AND: {logical_and}, ビットAND: {bitwise_and}")

3. シフト演算での桁あふれ

# 大きなシフト値に注意
large_number = 1000000
safe_shift = large_number << 10  # 問題なし
print(f"安全なシフト: {safe_shift}")

# シフト量が大きすぎる場合
try:
    # 非常に大きなシフトは避ける
    huge_shift = 1 << 1000  # Pythonは任意精度整数なので可能
    print(f"巨大な数の桁数: {len(str(huge_shift))}")
except MemoryError:
    print("メモリ不足")

デバッグとテストのコツ

1. ビット演算の可視化

def visualize_bits(number, width=8):
    binary = bin(number)[2:].zfill(width)
    return f"{number:3d} = {binary}"

def show_operation(a, b, op_name, result):
    print(f"{visualize_bits(a)}")
    print(f"{visualize_bits(b)}")
    print(f"{'=' * 15} {op_name}")
    print(f"{visualize_bits(result)}")
    print()

# 使用例
a, b = 12, 8
show_operation(a, b, "AND", a & b)
show_operation(a, b, "OR", a | b)
show_operation(a, b, "XOR", a ^ b)

2. ビット演算のテストケース

def test_bit_operations():
    # AND演算のテスト
    assert (5 & 3) == 1
    assert (15 & 7) == 7
    
    # OR演算のテスト
    assert (5 | 3) == 7
    assert (8 | 4) == 12
    
    # XOR演算のテスト
    assert (5 ^ 3) == 6
    assert (x := 42) ^ x == 0  # 自分自身とのXOR
    
    # シフト演算のテスト
    assert (1 << 3) == 8
    assert (16 >> 2) == 4
    
    print("全てのテストが通過しました")

test_bit_operations()

まとめ

Python のビット演算子を効果的に活用するポイント:

  • 基本演算子の理解: &, |, ^, ~, <<, >> の動作を正確に把握
  • パフォーマンス活用: 2の累乗計算や偶数判定での高速化
  • フラグ管理: 複数の状態を効率的に管理
  • 暗号化・ハッシュ: セキュリティ関連処理での活用
  • データ構造: ビットセットやブルームフィルタなどの実装

ビット演算子をマスターすることで、高性能で効率的なPythonプログラムが作成できるようになります。

■プロンプトだけでオリジナルアプリを開発・公開してみた!!

■AI時代の第一歩!「AI駆動開発コース」はじめました!

テックジム東京本校で先行開始。

■テックジム東京本校

「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。

<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。

<月1開催>放送作家による映像ディレクター養成講座

<オンライン無料>ゼロから始めるPython爆速講座