1. ビット演算の概要
現代のコンピュータでは、すべてのデータは2進数形式、すなわち0と1の2つの状態で格納されます。コンピュータが2進データに対して行う演算(加算、減算、乗算、除算など)はビット演算と呼ばれ、2進数の各ビットに対して操作を行う演算です。
ビット演算をよりよく理解するために、簡単な例を挙げます。2つの整数の加算を行う以下のコードがあるとします:
int a = 35; int b = 47; int c = a + b;
コンピュータはこれら2つの整数を2進数形式に変換してから、加算を行います:
35: 0010 0011 47: 0010 1111 ---------------- 82: 0101 0010
したがって、直接+、-、*、/演算子を使用するのと比較すると、ビット演算を適切に使用することで、マシン上でのコードの実行効率を大幅に向上させることができます。
2. ビット演算の一覧
| 記号 | 説明 | 演算規則 |
|---|---|---|
| & | と | 両方のビットが1のときのみ、結果が1になる |
| | | 或 | 両方のビットが0のときのみ、結果が0になる |
| ^ | 排他的論理和 | 2つのビットが同じなら0、異なれば1 |
| ~ | 否定 | 0は1になり、1は0になる |
| << | 左シフト | 各2進ビットをすべて左に数ビットシフトし、上位ビットは破棄し、下位ビットは0で埋める |
| >> | 右シフト | 各2進ビットをすべて右に数ビットシフトし、上位ビットは0または符号ビットで埋める |
3. ビット論理積演算子(&)
定義:演算に参加する2つのデータの2進ビットに対して「論理積」演算を行います。
演算規則:
0 & 0 = 0 0 & 1 = 0 1 & 0 = 0 1 & 1 = 1
まとめ:両方のビットが同時に1のときのみ結果が1になり、それ以外は結果が0になります。
例えば:3 & 5 即 0000 0011 & 0000 0101 = 0000 0001、したがって3 & 5の値は1です。
注意:負数は2の補数形式でビット論理積演算に参加します。
用途:
- クリア(ゼロにする):あるユニットをゼロにしたい場合、各ビットがすべて0の数値と論理積を取るだけで、結果はゼロになります。
- 数値の指定ビットを取得する:例えば、数値
X = 1010 1110の下位4ビットを取得するには、別の数値Y = 0000 1111を見つけて、X & Y = 0000 1110を実行すればXの指定ビットが得られます。 - 偶数・奇数の判定:最下位ビットが0か1かを判定することで偶数・奇数を決定でき、
if ((a & 1) == 0)の代わりにif (a % 2 == 0)を使用してaが偶数であるかを判定します。
4. ビット論理和演算子(|)
定義:演算に参加する2つのオブジェクトの2進ビットに対して「論理和」演算を行います。
演算規則:
0 | 0 = 0 0 | 1 = 1 1 | 0 = 1 1 | 1 = 1
まとめ:どちらか一方でも1であれば、その値は1になります。
例えば:3 | 5 即 0000 0011 | 0000 0101 = 0000 0111、したがって3 | 5の値は7です。
注意:負数は2の補数形式でビット論理和演算に参加します。
用途:
- 特定のビットを1に設定する:例えば、数値
X = 1010 1110の下位4ビットを1に設定するには、別の数値Y = 0000 1111を見つけて、X | Y = 1010 1111を実行すれば得られます。
5. 排他的論理和演算子(^)
定義:演算に参加する2つのデータの2進ビットに対して「排他的論理和」演算を行います。
演算規則:
0 ^ 0 = 0 0 ^ 1 = 1 1 ^ 0 = 1 1 ^ 1 = 0
まとめ:対応するビットが同じなら0、異なれば1です。
性質:
- 交換法則
- 結合法則:
(a ^ b) ^ c == a ^ (b ^ c) - 任意の数に対して
x、常にx ^ x = 0,x ^ 0 = x - 反射性:
a ^ b ^ b = a ^ 0 = a
用途:
- 指定ビットを反転する:例えば、数値
X = 1010 1110の下位4ビットを反転するには、別の数値Y = 0000 1111を見つけて、X ^ Y = 1010 0001を実行すれば得られます。 - 0と排他的論理和を取ると値は変わらない:例えば
1010 1110 ^ 0000 0000 = 1010 1110 - 2つの数値を交換する:
void Swap(int &a, int &b) {
if (a != b) {
a ^= b;
b ^= a;
a ^= b;
}
}
6. 否定演算子(~)
定義:演算に参加する1つのデータの2進ビットに対して「否定」演算を行います。
演算規則:
~1 = 1111 1110 ~0 = 1111 1111
すなわち:
~1 = -2 ~0 = -1
まとめ:0を1に、1を0にします。
用途:
- 数値の最下位ビットを0にする:例えば、
aの最下位ビットを0にするには、次のように表せます:a & ~1。~1の値は1111 1111 1111 1110となり、さらに「論理積」演算を行うと、最下位ビットは必ず0になります。
7. 左シフト演算子(<<)
定義:演算オブジェクトの各2進ビットをすべて左に数ビットシフトし、上位ビットは破棄し、下位ビットは0で埋めます。
例えば、a = 1010 1110,a = a << 2 将 aの2進ビットを左に2ビットシフトし、右に0を補うと、a = 1011 1000。
左シフトで破棄される上位ビットに1が含まれない場合、1ビット左シフトするごとに、その数は2倍されます。
8. 右シフト演算子(>>)
定義:ある数の各2進ビットをすべて右に数ビットシフトし、上位ビットは0または符号ビットで埋め、右側は破棄します。
例えば、a = a >> 2 将 aの2進ビットを右に2ビットシフトし、左に0または符号ビットを補います。これは数の正負によって異なります。
オペランドを1ビット右シフトするごとに、その数は2で割られます。
9. 複合代入演算子
ビット演算子と代入演算子を組み合わせると、新しい複合代入演算子が構成されます。それらは以下のとおりです:
&=例:a &= bは次と同等ですa = a & b|=例:a |= bは次と同等ですa = a | b>>=例:a >>= bは次と同等ですa = a >> b<<=例:a <<= bは次と同等ですa = a << b^=例:a ^= bは次と同等ですa = a ^ b
演算規則は、前述の複合代入演算子の演算規則と似ています。
異なる長さのデータに対するビット演算:
異なる長さの2つのデータに対してビット演算を行う場合、システムは両者を右端で揃えてからビット演算を行います。
「論理積演算」を例に説明すると、次のとおりです:
C言語では、long型は4バイトを占め、int型は2バイトを占めます。もしlong型データとint型データで「論理積演算」を行う場合、右端を揃えた後、左側の不足するビットは次の3つのケースで補われます:
- 整数型データが正の数の場合、左側に16個の0を補います。
- 整数型データが負の数の場合、左側に16個の1を補います。
- 整数型データが符号なし数の場合、左側にも16個の0を補います。
例えば:
long a = 123; int b = 1; long result = a & b;
long a = 123; unsigned int b = 1; long result = a & b;