ビット演算

ビット演算は、数値を二進数で表した時に、それぞれのビットに対して行われるような演算のことです。

ここでは、上記のプログラムで用いている「右シフト」と「論理積」を解説します。

右シフト

右シフトは、二進数の各ビットをLSB側(通常の二進数表記をした場合の右側)にずらす演算で、

0b00100010>>5Code language: Arduino (arduino)

のように>>という演算子で表されます。

例えば、0b00100010という二進数(「A」の点灯パターンの4行目)の右にひとつシフトすると、

二進数の各ビット十進数表記
76543210
元の値0010001034
右シフト後の値0001000117

のようになり、0b00010001という値が得られます。

例で示した 0b00100010>>5 は、0b00100010(=34)を右に5つずらすことを意味し、

二進数の各ビット十進数表記
76543210
元の値0010001034
右に1つシフト後の値0001000117
右に2つシフト後の値000010008
右に3つシフト後の値000001004
右に4つシフト後の値000000102
右に5つシフト後の値000000011

のように結果は0b00000001(= 1 )になります。上記のとおり、LSB側にあふれたビットは破棄されます。

論理積(AND)

ビット演算における論理積(AND)は、2つの二進数の各ビットをビットごとに掛け合わせる演算で、

0b00100010&1Code language: Arduino (arduino)

のように&という演算子で表されます(なお、&は前に数値がつかない場合は「後ろの変数のアドレスを示す」という全く別の意味になるのでご注意ください)。

論理積では、2つ二進数双方のビットが1の場合にのみ結果のビットが1になり、片方でも0の場合は0になります。表にまとめると以下のようになります。

入力値のビットの値出力値のビットの値
値その1値その2
000
010
100
111

例えば 0b01100111(= 103 )という値と 0b00110001(= 49 )という値の論理積を取ると、

二進数の各ビット十進数表記
76543210
値その101100111103
値その20011000149
論理積0010000133

のように、双方で1になっているビットのみが1を保持して結果は0b00100001(=33)になります。

例で示した0b00100010&1は、0b00100010(=34)と 1(=0b00000001)の論理積を取っており、

二進数の各ビット十進数表記
76543210
値その10010001034
値その2000000011
論理積000000000

のように、結果は0となります。

このように、ある値と1の論理和を取ると、その値のLSB(0ビット目)のみを取り出すことができ、右シフトと組み合わせることで特定のビットが0か1かを取得するのに便利です。

演算の優先度

ビット演算を含むC言語の演算には優先度があります。また、演算によって結合規則(左から右か、右から左か)が異なります。

例えば、右シフトは論理積よりも優先されるので、「0b00100010を右に5シフトし、1との論理積を取る」という演算は、以下のいずれの記載も可能です。

0b00100010>>5&1; // 0b00100010を右に5シフトし、1との論理積を取る(1になる)

1&0b00100010>>5; // 0b00100010を右に5シフトし、1との論理積を取る(1になる)Code language: Arduino (arduino)

2番目のものは「1と0b00100010の論理積を取り、右に5シフトする」という演算にはならないので注意しましょう。

どこが先に計算されるべきかを確実にするには、以下のように括弧を付けておくのが良いでしょう。

(0b00100010>>5)&1; // 0b00100010を右に5シフトし、1との論理積を取る(1になる)

1&(0b00100010>>5); // 0b00100010を右に5シフトし、1との論理積を取る(1になる)

(1&0b00100010)>>5; // 1と0b00100010の論理積を取り、右に5シフトする(0になる)Code language: Arduino (arduino)


それでは、ビット演算を用いたプログラムを組んでみましょう。プログラムが完成し動作確認を行ったら、次に示すプログラム例と見比べてみましょう。

前の記事

各ビットの値の取得