バイトとビット
ここでは、整数データ型の変数をビットごとに演算する方法について学習します。 コンピュータは 0 と 1 の2進数で動いています。普段プログラムで扱っている数字は10進数ですが、この2進数による計算はコンピュータの基本です。
バイトとビット
バイトとビットという単位は、コンピュータのメモリで使われるものです。メモリとは、コンピュータ内でデータやプログラムを記憶する装置のことで、CPUが直接読み書きできる主記憶装置とも呼ばれます。
ビット
メモリで扱う最小の単位は、1ビットです。1ビットは ON と OFF の状態を 0 と 1 (2進数)で表現します。それ以外の状態、値はありません。
一般に、nビットの情報量では2のn乗個までの情報を表現することができます。たとえば画像の場合、8ビットBMPといえば、2の8乗で256通りの色を扱えることになります。
バイト
1ビットを8個並べたセットが1バイトです。バイトはコンピュータで最もよく利用される単位で、情報の記録や伝達などのほとんどがバイト単位で処理されます。メモリのアドレス情報は、1バイト毎に割り当てられた番号で、CPUはバイト単位でアドレス情報を読み書きします。
1バイトの詳細
ビット 7 |6|5|4 |3|2|1|0
左端のビットのことを最上位ビット、右端のビットを最下位ビットと呼びます。
ビットパターン
1バイト1ビットが8個並んだものですから、2の8乗で256通りの整数を表現することができます。たとえば、10進数の0という数値を表現する場合は、00000000で 0 、 00000001 で 1 、00000010 で 2 といったように表現します。
10進数の 0 0|0|0|0|0|0|0|0
10進数の 1 0|0|0|0|0|0|0|1
10進数の 2 0|0|0|0|0|0|1|0
10進数の 3 0|0|0|0|0|0|1|1
10進数の 4 0|0|0|0|0|1|0|0
10進数の 5 0|0|0|0|0|1|0|1
10進数の 6 0|0|0|0|0|1|1|0
・・・
10進数の 255 1|1|1|1|1|1|1|1
データを上記のように 1 と 0 で表現したものを『ビットパターン』と呼びます。
ビット演算
ビット演算は、コンピュータで扱う最小の情報単位であるビットに対する演算ですから、演算速度は高速です。また、メモリの消費量を最小限に抑えることができます。ただし、算術演算子のように直感的に使えるものではありません。
ビット演算子の概要
ビットごとの論理演算には、次の 4 つの演算子が用意されています。
ビット演算子の一覧
演算子 | 演算 | 意味 |
---|---|---|
& | 論理積 | & を挟む両方の値が1である場合だけ1が返されます。
print sprintf("%04lo", 0011 & 0101), "\n"; > 0001 |
| | 論理和 | | を挟む片方あるいは両方の値が1であれば1が返されます。
print sprintf("%04lo", 0011 | 0101), "\n"; > 0111 |
^ | 排他的論理和 | ^ を挟む両方の値が異なるとき1が返されます。
print sprintf("%04lo", 0011 ^ 0101 ), "\n"; > 0110 |
~ | 否定 | ビットを反転します。 |
ビット演算の使い方
ビット演算は2進数以外にも、10進数、16進数などを処理することができます。
# 10進数 print 10 | 5, "\n"; > 15 print 10 | 2, "\n"; > 10 # 16進数 print 0x0a | 0x0f, "\n"; > 15 print 0x0a | 0x02, "\n"; > 10
10 と 5 の論理和が15というのは、以下のような処理が行われたうえでの結果です。
- 10を2進数であらわす → 00001010
- 5を2進数であらわす → 00000101
- 10と5の2進数で論理和を行う → 00001111
- 結果を16進数で出力(0x略) → 15
ただし、数値を文字列としてビット演算した場合、以下のようになります。
print "10" | "5", "\n"; > 50 print "10" | "2", "\n"; > 30
ここでは、演算のための長さを統一するために、短いほうの右側に0のビットを付け加えています。"10" | "5" が演算対象となっている場合は、一度"10" | "50" と置き換えてから処理しています。
文字列も処理することができます。文字列同士のビット演算では、ASCIIコードを基準に処理します。
print "a" | "b", "\n"; > c
わかりやすいように、1 と 0 を論理積、論理和、排他的論理和の処理にかけた場合の表にしました。
論理積・論理和・排他的論理和の処理結果一覧
値A | 値B | 論理積(A & B) | 論理和(A | B ) | 排他的論理和(A ^ B) | 否定(~A) |
---|---|---|---|---|---|
1 | 1 | 1 | 1 | 0 | 0 |
1 | 0 | 0 | 1 | 1 | 0 |
0 | 1 | 0 | 1 | 1 | 1 |
0 | 0 | 0 | 0 | 0 | 1 |
3.シフト演算子
ビット単位での演算子には、ビット演算子の他にシフト演算子もあります。ここでいうシフトというのは、数値を2進数で表し、全ケタを右や左へずらすことです。
シフト演算子には、次の 2 つの演算子が用意されています。
演算子 | 使い方 | 意味 |
---|---|---|
<< | A << B | Aの値をBの数だけ左へシフトする。 |
>> | A >> B | Aの値をBの数だけ右へシフトする。 |
それでは、ためしに左シフト演算子を使ってみましょう。
print 5 << 1, "\n"; > 10
これは、10進数の 5 に対して1ビットシフトするということです。1ビットソフトするというのは、2進数の右端の数字をはずして、左端に0を埋めます。 5は2進数で00000101 なので、これを上のように操作すると 00001010 、つまり10進数の10になります。
5を左へ1ケタずらすと2倍の10になります。2進数で右端に0をくっつけるというのは、2倍にすることを意味します。10進数で右端に0をつければ10倍になるのと同じことです。
次に、右シフト演算子を使ってみましょう。
print 10 >> 1, "\n"; > 5
右シフトは2分の1倍になります。2進数で右端の数値を取るというのは、2分の1倍にすることを意味します。
2で割りきれない奇数を右へ1ケタずらしてみましょう。
print 15 >> 1, "\n"; > 7
割り切れない場合は、端数を切り捨てます。