C++ ビット演算 書いて覚えるための初心者自己中記事
二進数の演算にはビット演算というものがある
五種類あって
AND 論理積
OR 論理和
XOR 排他的論理和
NOT 論理否定
ビットシフト
ANDの演算子は
&
二項演算子だ。
0011
&)0101
ーーーーー
0001
上下の数値に対してANDは両方とも1の時だけ1を出している。
これを利用して
01111010
&)00001111
ーーーーーーーーー
00001010
とする。取り出したいビット部分は1で。
必要ないビット部分は0で計算させると
ほしいビット部分が抜き出される。
これをマスキングという。
ビット演算子の優先順位は低い
a & b == c
の場合など
a & (b == c)
こうなる。
OR(論理和)の場合
演算子は |
0011
|) 0101
ーーーーー
0111
両方、またはどちらかが1の場合は1を出している。
これを利用して
01001101
|) 10000111
ーーーーーーーーー
11001111
とする。
上書きしたい部分は1で、
そのまま残したい部分は0でいける。
XOR(排他的論理和)の場合
演算子は ^
0011
^) 0101
ーーーーー
0110
片方が1の場合は1
それ以外は0
上下で違っていないと気が済まない感じ
これを利用して
01111010
^) 00001111
ーーーーーーーーー
01110101
となる。
反転させたいビット部分には1を
そのままにしたい部分には0を。
ビット反転というらしい。
NOT(論理否定)の場合
演算子は ~
~)01
ーーー
10
ただ反転した。
これを利用するにはANDも使って
~)00011111
ーーーーーーーーー
11100000
反転させてからANDでやったみたいにすると
01111010
&)11100000
ーーーーーーーーー
01100000
NOTをつかうとANDの結果が逆になる
ビットシフトの場合
演算子は >> (右シフト) << (左シフト)
00010101
>>) 2
ーーーーーーーー
00000101
00010101
<<) 4
ーーーーーーーー
01010000
シフトしている。
溢れたビットは切り捨てられる。
負の数を右シフト>> するとビットの無くなる部分が1で埋められる。
10010010
>>) 4
ーーーーーーーー
11111001
これを算術シフトという。
また、一番上を0で埋めることを論理シフトという。
算術シフトは
負の数を2の補数という形式で表現している環境
で使われる環境依存
???
実際の使用例
int main() { int x = 105054; for (int i = 1,count = 1; i <= x; i <<= 1,++count) {// i <<= 1 で1桁づつ左にビットシフト if ((x & i) == 0) {// 左に1づつビットシフトしているi とx を&して結果が1ならxのその桁は1 cout << count << "ビット目が0" << endl; } else { cout << count << "ビット目が1" << endl; }
} system("pause"); }
//output
1ビット目が0
2ビット目が1
3ビット目が1
4ビット目が1
5ビット目が1
6ビット目が0
7ビット目が1
8ビット目が0
9ビット目が0
10ビット目が1
11ビット目が0
12ビット目が1
13ビット目が1
14ビット目が0
15ビット目が0
16ビット目が1
17ビット目が1
慣れないと非常にややこしいな・・。
次。
ビットフラグ
上記の感覚でビットごとにフラグとしての役割を持たせる。
int Bit(int x) { return 1 << x; } const int SHOW_X = Bit(0); const int SHOW_Y = Bit(1); const int SHOW_Z = Bit(2); void Show(int flags) { cout << (flags & SHOW_X ? 'X' : 'x') << (flags & SHOW_Y ? 'Y' : 'y') << (flags & SHOW_Z ? 'Z' : 'z') << endl; } int main() { Show(0); // 0 Show(SHOW_X); // 1 Show(SHOW_Y | SHOW_Z); // 11 Show(SHOW_X | SHOW_Y | SHOW_Z); // 111 system("pause"); }
//output
xyz
Xyz
xYZ
XYZ
Show();
に入れる前にint変数 flags に入れたほうがすっきるする。
int main() { int flags = SHOW_X | SHOW_Y | SHOW_Z; Show(flags); // 1 system("pause"); }
このflags に対してフラグを追加したり削除したりしたい。
int main() { int flags = SHOW_X; flags |= SHOW_Y;//SHOW_Yを追加した flags &= ~SHOW_Y;// AND NOT でSHOW_Y を削除した flags ^= SHOW_Y;//XOR でSHOW_Yを反転させた Show(flags); / system("pause"); }
これらはORで複数まとめてもOK
ここまで