2部 Perl言語仕様

付録 ビット演算

バイトとビット

ここでは、整数データ型の変数をビットごとに演算する方法について学習します。 コンピュータは 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というのは、以下のような処理が行われたうえでの結果です。

  1. 10を2進数であらわす → 00001010
  2. 5を2進数であらわす → 00000101
  3. 10と5の2進数で論理和を行う → 00001111
  4. 結果を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

割り切れない場合は、端数を切り捨てます。

関連記事