コンピュータが認識するデータは0と1の羅列であるため、時には情報の最小単位としてビットで考える必要が出てきます。
通常1バイトというと8ビットに相当します。
8ビットのことをオクテットともいいます。
この8ビットというのは「0か1」のビットが8つ連なっていますので「ON」または「OFF」といった2種類のフラグで考えると、8つの情報を持つことができることになります。
■論理和と論理積
例えば1バイト内にゴミ捨て曜日を収めることにした場合、「00000000」と8つあるうちの先頭(左端)から「日曜」「月曜」...「土曜」「最後は予備」と割り当てるように決めて、「水曜」と「土曜」のビットを立てることを考えると
$gomi= bindec("00010000") | bindec("00000010"); // 「00010010」
と「|」を使って「論理和」で書くことができます。
ちなみにこの場合、立ってるビットがカブってないので
$gomi= bindec("00010000") + bindec("00000010"); // 「00010010」
と算術加算しても同じ値になります。
「| 論理和」では左側と右側のどちらかが1ならそのビット位置は1になります。
「& 論理積」を使うと、左側と右側の両方が1ならそのビット位置が1になるので上記の場合だと「00000000」になります。
$gomi= bindec("00010000") & bindec("00000010") // 「00000000」
「月曜」「水曜」「金曜」に変更になった場合は
$gomi= bindec("01000000") | bindec("00010000") | bindec("00000100"); // 「01010100」
このように、たった1バイトの中に一週間のゴミ出し曜日を収めることができました。
∩( ・ω・)∩ばんじゃーい
■排他的論理和
次に「排他的論理和」を使ってみます。
これは「論理和」というように「|」と似ていますが左右両側とも1だと打ち消し合って0になるという意味で「排他的」なわけです。
bindec("11110000") ^ bindec("10000000") は「01110000」になります。
10進数で書くと、240 ^ 128 が112ということになります。
■否定
次は「否定」を使ってみます。
否定の場合は左側と右側を演算するものではなくて、「~」直後の数値をビット反転させた値に変えます。
~bindec("10000000") なら「01111111」に
~bindec("00001111") なら「11110000」になります。
のつもりでしたが、実際に結果を出力させてみると
echo ~bindec("10000000") は「-129」、
echo ~bindec("00001111") は「-16」となってしまいます。
この値を2進数に直すと、
echo decbin(~bindec("10000000")) は「11111111111111111111111101111111」
echo decbin(~bindec("00001111")) は「11111111111111111111111111110000」
のように32ビットつまり4バイトとして表示されていたようです。
var_dump(bindec("10000000"));としてみると「int(128) 」の表示になります。
つまりPHPのint型は4バイトなのでビット反転では32ビットの上位24ビットがすべて反転されて思わぬ値になっていたようですね。
ということでこの場合は
~bindec("10000000") を ~bindec("10000000") & bindec("11111111") と書いて論理積でマスク(必要なビットだけ抜き出す)する必要があります。
確認してみます。
echo decbin(~bindec("10000000") & bindec("11111111")) は「1111111」という表示になりました。
∩( ・ω・)∩ばんじゃーい
■ビットシフト
さてお次は「ビットシフト」を使ってみます。
まずは右シフト「>>」
echo bindec("10000000") >> 1; これは128が64になります。
echo decbin(bindec("10000000") >> 1); 2進数で確認すると「1000000」のように1が右に1つずれていることが確認できます。
左シフト「<<」
echo bindec("10000000") << 1; これは128が256になります。
echo decbin(bindec("10000000") << 1); 2進数で確認すると「100000000」のように1が左に1つずれて9ビットになっていることが確認できます。
これまでに書いてきたビット演算子にはそれぞれビット演算と代入を同時にできる演算子が用意されています。
$a = $a & $b なら $a &= $b
$a = $a | $b なら $a |= $b
$a = $a ^ $b なら $a ^= $b
$a = $a << $b なら $a <<= $b
$a = $a >> $b なら $a >>= $b