1. ホーム
  2. python

[解決済み] ビット演算とその使い方

2022-12-15 22:54:09

質問

このコードを考えてみましょう。

x = 1        # 0001
x << 2       # Shift left 2 bits: 0100
# Result: 4

x | 2        # Bitwise OR: 0011
# Result: 3

x & 1        # Bitwise AND: 0001
# Result: 1

Python(や他の言語)の算術演算子は理解できるのですが、「ビット演算子」はあまりよく理解できていませんでした。上の例(Pythonの本から)では、左シフトはわかるのですが、他の2つはわかりません。

また、ビット演算子は実際に何のために使われるのでしょうか?いくつかの例を教えていただきたいです。

どのように解決するのですか?

ビット演算子は、複数ビットの値に対して動作する演算子ですが、概念的には一度に1ビットずつ動作する演算子です。

  • AND が1の場合のみ ともに の場合のみ 1 となり、それ以外は 0 となります。
  • OR が1であれば またはその両方 の場合は 1、それ以外は 0 です。
  • XOR が 1 である場合のみ ちょうど1 のときだけ 1 になり、それ以外は 0 になります。
  • NOT はその入力が 0 の場合のみ 1 で、それ以外は 0 です。

これらはしばしば真理値表として最適に示すことができます。 入力の可能性は上部と左側にあり、結果のビットは、入力の交差点に示される 4 つの値 (NOT の場合は 1 つの入力のみなので 2 つ) のうちの 1 つになります。

AND | 0 1     OR | 0 1     XOR | 0 1    NOT | 0 1
----+-----    ---+----     ----+----    ----+----
 0  | 0 0      0 | 0 1       0 | 0 1        | 1 0
 1  | 0 1      1 | 1 1       1 | 1 0

一例として、整数の下位4ビットだけが欲しい場合、15(2進数1111)とANDするわけです。

    201: 1100 1001
AND  15: 0000 1111
------------------
 IS   9  0000 1001

この場合、15の0ビットは効果的にフィルターとして機能し、結果のビットも0になるように強制します。

さらに >><< はビット演算子としてよく使われるもので、値をあるビット数だけ左右にそれぞれシフトさせ、シフトさせる側のビットを捨て、反対側のビットをゼロにするものです。

ですから、たとえば

1001 0101 >> 2 gives 0010 0101
1111 1111 << 4 gives 1111 0000

Pythonの左シフトは、ビットが破棄される固定幅を使用していないという点で珍しいことに注意してください。多くの言語はデータ型に基づいた固定幅を使用しますが、Pythonは単に余分なビットに対応するために幅を拡張しています。Pythonでビットを捨てる動作をさせるためには、左シフトの後にビット単位の and のように、8ビットの値を4ビット左にシフトさせることができます。

bits8 = (bits8 << 4) & 255

それを踏まえて、ビット演算子のもう一つの例として、4ビットの値が2つあって8ビットにまとめたい場合、3つの演算子すべて( left-shift , andor ):

packed_val = ((val1 & 15) << 4) | (val2 & 15)

  • & 15 オペレーションは両方の値が下位4ビットのみを持つことを確認します。
  • << 4 は4ビット左シフトして val1 を 8 ビット値の上位 4 ビットに移動します。
  • | は単にこの二つを結合したものです。

もし val1 が7で val2 は4です。

                val1            val2
                ====            ====
 & 15 (and)   xxxx-0111       xxxx-0100  & 15
 << 4 (left)  0111-0000           |
                  |               |
                  +-------+-------+
                          |
| (or)                0111-0100