Pythonのビット演算子(論理積、論理和、排他的論理和、反転、シフト)

Modified: | Tags: Python

Pythonにはビット演算子として&, |, ^, ~, <<, >>が用意されている。2進数で表した整数intの各ビットに対して、それぞれ論理積、論理和、排他的論理和、ビット反転、左ビットシフト、右ビットシフトを行う。

整数を2進数、8進数、16進数で記述する方法や、bin(), oct(), hex()format()を使った2進数、8進数、16進数の数値、文字列の変換については以下の記事を参照。

整数intの2進数表記における1の数をカウントする方法については以下の記事を参照。

また、ビット単位の演算ではなく、真偽値bool型(True, False)に対する論理演算(ブール演算)については以下の記事を参照。&, |ではなく、and, orを使う。

論理積(AND)、論理和(OR)、排他的論理和(XOR)の入出力

論理積(AND)、論理和(OR)、排他的論理和(XOR)の各ビットに対する入力と出力の関係は以下の表の通り。

入力1 入力2 論理積(AND) 論理和(OR) 排他的論理和(XOR)
1 1 1 1 0
1 0 0 1 1
0 1 0 1 1
0 0 0 0 0

ビット単位論理積(bitwise AND): &演算子

&演算子によるビット単位論理積(bitwise AND)の例。bin()で2進数表記の文字列に変換した結果を合わせて出力している。

x = 12  # 0b1100
y = 10  # 0b1010

print(x & y)
print(bin(x & y))
# 8
# 0b1000

ビット単位論理和(bitwise OR): |演算子

|演算子によるビット単位論理和(bitwise OR)の例。bin()で2進数表記の文字列に変換した結果を合わせて出力している。

x = 12  # 0b1100
y = 10  # 0b1010

print(x | y)
print(bin(x | y))
# 14
# 0b1110

ビット単位排他的論理和(bitwise XOR): ^演算子

^演算子によるビット単位排他的論理和(bitwise XOR)の例。bin()で2進数表記の文字列に変換した結果を合わせて出力している。

x = 12  # 0b1100
y = 10  # 0b1010

print(x ^ y)
print(bin(x ^ y))
# 6
# 0b110

負の整数に対するビット演算

負の整数に対してビット演算を行うと、値が2の補数形式で表現されているものとして処理される。

ただし、負の整数をbin()format()などで2進数の文字列に変換すると、2の補数形式ではなく絶対値にマイナス符号が付いた形になる。

x = -9

print(x)
print(bin(x))
# -9
# -0b1001

2の補数表現の文字列を取得したい場合は、4bitなら0b1111(=0xF)、8bitなら0xFF、16bitなら0xFFFFのように、必要なビット桁数の最大値とのANDを取る。

2の補数表現(各ビットを反転させて1を加える)の文字列が取得できる。

print(bin(x & 0xFF))
print(format(x & 0xFF, 'b'))
# 0b11110111
# 11110111

ゼロ埋めの指定がないと先頭の0が省略されてしまうので注意。

print(bin(x & 0b1111))
print(format(x & 0b1111, 'b'))
# 0b111
# 111

print(format(x & 0b1111, '#06b'))
print(format(x & 0b1111, '04b'))
# 0b0111
# 0111

ビット反転: ~演算子

~演算子によるビット反転の例。

Pythonにおけるビット反転は、単純に各ビットを反転した値ではなく、~xに対して-(x+1)となる値を返す。

-(x+1)は入力値xを2の補数形式とみなして、すべてのビットを反転した値と等価。

上述のように、Pythonでは負の整数をbin()format()などで2進数の文字列に変換すると、2の補数形式ではなく絶対値にマイナス符号が付いた形になるので、~xをそのまま文字列に変換しても元の値のビットが反転した文字列にはならない。

x = 9  # 0b1001

print(~x)
print(bin(~x))
# -10
# -0b1010

AND演算を行い、2の補数表現の文字列にすると、元の値のビットが反転していることが分かる。例えば、4桁のビット列をそのまま反転したビット列(符号ビットなし)を取得するには、AND演算を行った値に対してformat()'04b'のようにゼロ埋めする。

print(bin(~x & 0xFF))
print(format(~x & 0b1111, '04b'))
# 0b11110110
# 0110

ビットシフト: <<演算子、>>演算子

ビットシフト演算子<<, >>による、左ビットシフト、右ビットシフトの例。

x = 9  # 0b1001

print(x << 1)
print(bin(x << 1))
# 18
# 0b10010

print(x >> 1)
print(bin(x >> 1))
# 4
# 0b100

負の値に対しては符号ビットが拡張されてシフトされ、正負の符号は変わらない。負の値は左側にずっと1が並んでいるイメージ。

x = -9
print(bin(x))
print(bin(x & 0xFF))
# -0b1001
# 0b11110111

print(x << 1)
print(bin(x << 1))
print(bin((x << 1) & 0xFF))
# -18
# -0b10010
# 0b11101110

print(x >> 1)
print(bin(x >> 1))
print(bin((x >> 1) & 0xFF))
# -5
# -0b101
# 0b11111011

数値で考えるとよく分からなくなるので、2の補数表現の文字列で考えたほうがいい。

関連カテゴリー

関連記事