ビット演算は、昔はメモリ領域の節約のために用いられる手法でしたが、最近ではメモリも潤沢にあるので、使う機会も減りました。
ですが、使いどころによっては様々な状態を表す演算として有用となりますので、いつでも使えるようにしておくことが望ましい機能です。
本記事では、Rubyにおけるビット演算について解説します。
記事内に記載しているプログラムは、Ruby2.7.1を使って動作確認をしています。
Rubyのビット演算
Rubyのビット演算について、以下の内容を解説します。
- Rubyでのビット演算の扱い方
- AND演算
- OR演算
- XOR演算
- NOT演算
- 左シフト演算
- 右シフト演算
- ビットのフラグ確認
- Arrayでのビット演算子
Rubyでのビット演算の扱い方
ビット演算はその名の通り、1ビット単位で演算を行うので、プログラムも2進数で表現していきます。
Rubyで2進数で表現するには、先頭に 0b をつけます。
a = 0b1010 puts a # -> 10
2進数のまま表示するには、printfメソッドで書式指定(%b)を使います。
printf("%08b\n", a) # -> 00001010
マイナス値を上記の方法で表示すると、2の補数表現で表されます。
a = -0b1010 puts a # -> -10 printf("%08b\n", a) # -> ..110110
上記の書式指定では、8桁固定としているため、省略表示となってしまいます。
きっちり8桁固定とする場合には、下位8ビットを抜き出すことで表すことができます。
printf("%08b\n", a & 0b11111111) # -> 11110110
AND演算
AND演算を行うには、演算子&を使います。
AND演算は演算するビット同士が1であれば結果は1、それ以外の組み合わせは0となる計算を行います。
a = 0b1010 b = 0b0110 result = a & b puts result # -> 2 printf("%08b\n", result) # -> 00000010
上記のプログラムは、「0b1010」と「0b0110」のAND演算になるので、結果は「0b0010」となって2となります。
OR演算
OR演算を行うには、演算子|を使います。
OR演算は演算するどちらかのビット1であれば結果は1、両方のビットが0であれば結果は0となる計算を行います。
a = 0b1010 b = 0b0110 result = a | b puts result # -> 14 printf("%08b\n", result) # -> 00001110
上記のプログラムは、「0b1010」と「0b0110」のOR演算になるので、結果は「0b1110」となって14となります。
XOR演算
XOR演算を行うには、演算子^を使います。
XOR演算は演算するビットが0と1で異なる場合は結果は1、ビットが同じ0同士または1同士であれば結果は0となる計算を行います。
a = 0b1010 b = 0b0110 result = a ^ b puts result # -> 12 printf("%08b\n", result) # -> 00001100
上記のプログラムは、「0b1010」と「0b0110」のXOR演算になるので、結果は「0b1100」となって12となります。
NOT演算
NOT演算を行うには、演算子~を使います。
NOT演算は1つ値の持つ各ビットを反転させる計算を行います。
a = 0b1010 result = ~a puts result # -> -11 printf("%08b\n", result) # -> ..110101 printf("%08b\n", result & 0b11111111) # -> 11110101
上記のプログラムは、「0b1010」の各ビットを反転させて1を加えた補数表現となります。
左シフト演算
左シフト演算は、演算子<<を使って、ビットをそのまま指定した数だけ左に移動させます。
左端はそのまま桁あふれとなり、右端から0が入ってきます。
a = 0b1010 result = a << 2 puts result # -> 40 printf("%08b\n", result) # -> 00101000
上記のプログラムは、「0b1010」を2桁左に移動して、「0b101000」となって40となります。
左シフトするごとに2倍になっていくことになります。
右シフト演算
右シフト演算は、演算子>>を使って、ビットをそのまま指定した数だけ右に移動させます。
右端は切り捨てられ、左端は正の数であれば0、負の数であれば1が入って、符号をそのまま引継ぎます。
a = 0b1010 result = a >> 2 puts result # -> 2 printf("%08b\n", result) # -> 00000010
上記のプログラムは、「0b1010」を2桁左に移動して、「0b0010」となって2となります。
右シフトするごとに1/2になっていくことになります。
端数は切り捨てられ、最終的に0となります。
なお、負の数に対して、>>による右シフト演算を行うと、負数のまま右シフトとした補数表現となります。
ビットのフラグ確認
Rubyでは任意のビットが立っている(1かどうか)を、メソッド [] で調べることができます。
0が最下位ビットです。
a = 0b1010 puts a[0] # -> 0 puts a[1] # -> 1 puts a[2] # -> 0 puts a[3] # -> 1
Arrayでのビット演算子
RubyではArray同士にビット演算子を使うことができます。
(正確にはメソッドとして定義されています。)
&で演算すると、両方のArrayに含まれる要素からなる新しいArrayを返します。重複する要素は省かれます。
| で演算すると、両方のArrayのいずれかに含まれる要素をすべて含む新しいArrayを返します。重複する要素を省かれます。
a = [1, 3, 5] b = [1, 2, 3] result = a & b p result # -> [1, 3] result = a | b p result # -> [1, 3, 5, 2]
まとめ
Rubyのビット演算についてまとめると、以下となります。
- Rubyで2進数を扱うには、値の先頭に0bを付ける。
- ビット演算は各ビットに対して演算を行う。
- シフト演算は各ビットを移動させて演算を行う。
- Rubyではビットごとのフラグ確認や、Arrayに対してビット演算子を使うことができる。
通常あまり使う機会はないかもしれませんが、桁に意味を持たせてフラグ管理したい場合などに使ってみてはいかがでしょうか。
今回は、Rubyのビット演算について解説しました。
以上、参考になれば幸いです。
コメント