ビット演算なんて何に使えるんだ?という人のために
複数の選択状態を示す10進数値から情報を取り出す時はビットマスクで[&](ビットごとのAND)を使ってビット演算する
前回のお話
『2進数と10進数の対応を眺めることで、複数の選択状態をたった一つの10進数数値で表現することができる』
という前回の記事の内容を初めて知った人は、複数の選択状態を示す10進数を求める方法、
各桁のみ1である2進数、1(00001) , 2(00010) , 4(00100) , 8(01000) , 16(10000) … 等が選択肢の選択状態を表現しているとして
E D C B A という選択肢がある場合、
[ABC] を選択なら、[00111]、
[CD] を選択なら[01100] になるので
10進数値は、 [ABCを選択] = [00111] = 4+2+1 = 7、
[CDを選択] = [01100] = 8+4 = 12
という10進数値で表現できる。
という内容を紹介しました。
前回の最後に、
「10進数にした値から個別に選択しているのを取り出す時はどうするんだ?」
という質問に対する方法を紹介すると予告していました。
最初に回答を書きますと、
「複数の選択状態を示す10進数値から情報を取り出す時はビットマスクで[&](ビットごとのAND)を使ってビット演算する」
となります。今回はその内容を紹介しています。
ビット演算について
まずは最近、寄付してください、あなたが寄付してくれるとわしらは暮らしてゆけるので、はやく助けて~さもないと広告とか入れるしかないけど広告入れないポリシーは捨てられんのよ~などと大画面で仕送りを催促してくるようになっている wikipedia さんから引用します
ビット演算(ビットえんざん)とは、ひとつあるいはふたつのビットパターンまたは二進数を個々のビットの列として操作することである。
CPU設計の観点からは、ビット演算は簡単な論理回路で実現できるが、四則演算、特に乗除算は複雑な論理回路を必要とするため、多くのコンピュータでは、ビット演算は加減算より若干速く、乗除算よりずっと高速である。
ビット演算はビットマスクと呼ばれる手法を用いたフラグ管理などに用いられるほか、その並列性からオートマトン実装に用いられる場合もある(→Bitapアルゴリズム)。
(wikipediaより引用)
「一見さんお断り」な意味がわかりづらい文章っぽいですが、今回の記事内容としては
「二進数を個々のビットの列として操作」「ビットマスクと呼ばれる手法を用いたフラグ管理などに用い」という部分を紹介しているような感じになります。
このwikipediaの記事を見てゆくと、いろんなビット演算のタイプが紹介されていますので、興味が出てきた人は改めて読まれることを推奨します。もしかすると、原森記事のような活用例を紹介してる記事ではないので、眠たくなってしまうか、よくわからない壁にぶち当たって、何に使えるんだよこれ、となってしまうもしれませんが…。
今回は、そういうwikipediaに書いてあるようなビット演算各種の内容を研究しよう、というプログラマ以外には全く関係のないことを紹介するのがテーマではなく、
ビット演算子の一つ「AND」を使うとこんな感じで便利なことができる、という紹介になっています。
また、画像加工の「マスク」の概念とビットのような、全く関係ないものどうしの「アイデア(考え方)を組み合わせることでアハ体験できる」という記事内容になっています。
ここまでで、読む気が無くなった人はさようなら。
前回記事にあった最後の質問と回答
質問「1つの数値化したものから個別に選択しているのを取り出す時はどうするんだ?」
回答は今回の見出し2レベルのタイトル
「複数の選択状態を示す10進数値から情報を取り出す時はビットマスクで[&](ビットごとのAND)を使ってビット演算する」
について、以下説明してみたいと思います。
ビットごとの、とか書いてるけどそのビットってなんやねん
ビットマスクで[&](ビットごとのAND)を使ってビット演算する
言葉だけ聞くと、古くは8ビットパソコンや、セガメガドライブ本体に 16-BIT と書いてあったり、ネオジオのCMで「100メガショック!100メガビットの大容量」などのセリフが脳内に浮かぶ人は40代以上の人だと思いますが、最近ならネット回線速度などで、100メガビーピーエス!などと聞いたことがあるかもしれません。
ビーピーエスは、1秒間に○○ビット分のデータ転送が理論上はできます、というものですが今回記事には全く関係なかったりします。
「ビットというのは最小単位です」とか「8bit=1B(バイト)」などの説明が検索すると書いてあったりしますが、いろんな意味や使い方がある言葉ですので、前回や今回の記事内容では、『 0 か 1 のどちらかになってる2進数の1つの桁のこと』を採用したいと思います。
10進数の 7 を5桁の2進数にすると、00111 となりますが、
0 …5桁目
0 …4桁目
1 …3桁目
1 …2桁目
1 …1桁目
のような各桁をビットと呼んで、ビットごと、というのはその桁ごと、と言う意味です。
ANDは「2人で投票し2人とも[賛成(1)]以外は、結論が[反対(0)]になる演算」
ビットマスクで[&](ビットごとのAND)を使ってビット演算する
電卓で普通に使っている演算子として「+」「-」「*」「/」がありますが、これはほとんどの人が知ってる知識だと思います。
0 + 0 = 0(10進数) とか 0000 + 0000 = 0000(2進数)
0 + 1 = 1(10進数) とか 0000 + 0001 = 0001(2進数)
1 + 0 = 1(10進数) とか 0001 + 0000 = 0001(2進数)
1 + 1 = 2(10進数) とか 0001 + 0001 = 0010(2進数)
こういう計算の間にある「+」を演算子といいますが、
AND演算子、「AND」は以下のような計算になっています。
0 AND 0 = 0
0 AND 1 = 0
1 AND 0 = 0
1 AND 1 = 1
論理積とか、なんだか聞いたことあるけど考えるだけでなんだか嫌になる人もいるかもしれませんので、あまり深く考えず、
ANDは、二人で賛成か反対かを投票することで例えてみれば、二人が[賛成]した時だけ[賛成]となるような計算になっています。
この時の賛成を1、反対を0という数値で表現します。
ビットごとのANDってなんだ?
ビットマスクで[&](ビットごとのAND)を使ってビット演算する
ビットは「2進数の桁を表現するもの」で、ANDは「両方が賛成(1)した時だけ賛成(1)となる演算」なので、
ビットごとのAND、とは、2進数で表現した数値の各桁(=ビット)ごとにAND計算する、というものになります。
例:A=5、B=3の場合、A と B の ビットごとのANDの結果である C の値は
A: [0101] (5を2進数に変換)
B: [0011] (3を2進数に変換)
C: [0001] (A と B の[ビットごとのAND]の結果)
となります。
2進数に変換した A と B のビット(2進数の各桁)ごとのAND(1と1なら1、それ以外は0になる)は、縦に 0 と 1 の並びを比較して両方が 1 の桁だけ 1 で、それ以外は 0 なので、それぞれのANDの結果を並べてみた結果、C のように 0001 となりました。
結果である 0001(2進数) を10進数にすると、C=1(10進数)になっています。
これがビットごとのANDという計算ですが、初めて知った人にとってはまだ「ビット演算なんて何に使えるんだ?」という感想かもしれません。(計算例の 5 と 3 に特に意味がないからです)
ビットごとのANDの演算子はほとんどのプログラムで「&」記号を使ってます
ビットマスクで[&](ビットごとのAND)を使ってビット演算する
プログラムではこの「ビットごとのAND」という演算子は「&」(アンド記号が1個だけ)になってます。
なので、さっきの例は A=0101 , B=0011 なら、C=0001なので、
0101 & 0011 = 0001 (2進数)
5 & 3 = 1 (10進数)と表現されます。
この段階でも、まだまだこういう計算であると紹介しているだけです。
※はやくあるある言いたい、のような雰囲気のなんだかもったいぶった感じになってきました…
「マスク」は作業部分の選択範囲を示したり、それ以外を触らないようにするためのもの
画像加工の分野で「マスク」という選択範囲以外の部分を表示や非表示にしたり、選択範囲の部分のみ画像を処理するような、画像加工で良く出てくる言葉がありますが、今回紹介している「ビットマスク」のマスクもニュアンス的に、画像加工時に操作しない部分をマスクする、という意味を含むようなものになります。
ビット演算の「&」で計算する時に、ある特定の値でマスクする、この値が「ビットマスク」
ビットマスクで[&](ビットごとのAND)を使ってビット演算する
ビットマスクは、ビット(2進数の各桁)をマスクするもの、となります。そのビットごとにAND演算する時のマスクはどんな値なのか?
ヒントはAND演算が二つとも 1 の時は 1 になり、それ以外は 0 となる演算です。
答え:ビットマスクは、調べたい桁のみが 1 である数値、です。
例えば、10進数の 3 を2進数にした時の1桁目が 1 か 0 かを調べたい時、1桁目を調べるためのビットマスクを2進数にした時、[ABCD]だったとします。
[0011](調べる数値) & [ABCD](ビットマスク) ならば、
Dが 0 だと、1桁目のANDが絶対に 0 になってしまうので、Dは 1 しかあり得ないからです。
そして調べたい桁以外は 0 にしておくと、[&]で各桁ごとに AND すると、関係のない桁はすべて 0 になる、ということなのです。
具体的には、4桁の2進数の場合のビットマスクは、
0001(=1)、0010(=2)、0100(=4)、1000(=8) となります。
これは前回の記事で、覚えておくと便利とか書いていた、2の階乗の数値です。
複数の選択状態を示す10進数値から選択しているという情報を取り出す時は、ビットマスクと[&]計算すれば、簡単に判定できる
ビットマスクで[&](ビットごとのAND)を使ってビット演算する
人は、A = 7(10進数) = 111(2進数) なら、一目で、全部選択してる!などと判定できますが、コンピュータは計算機なので、計算で答えを出し、人がそれに意味づけをする必要があります。
なので、7&1=1 , 7&2=2 , 7&4=4 などとビットマスクで演算し、その計算結果を使ってプログラムで以降の処理を書くということになります。(※プログラマって書くのが長いので人と書きました…なんだか急にゲシュタルト崩壊する時がありますが…)
ですがいきなり、7を1や2や4で & すると良い、などと言われても意味がわからないかもしれません。
そこで、2進数に変換して、7は111、1桁目のみ1なのは 001(2進数) = 1(10進数)、2桁目のみが1なのは 010(2進数) = 2(10進数)、3桁目のみ1なのは 100(2進数) = 4(10進数)、なので、それぞれのビットマスクで2進数の桁ごとにANDを計算すると、選択しているかどうかを判定するアイデアに使える、ということが理解しやすくなるかと思います。
複数選択状態を示す10進数値と、ビットマスクを[&](ビットごとのAND)で計算すると、選択しているかしていないかを計算することができる。なぜなら、ビットマスクとの[&]を計算すると、必ず結果は、[0]又は[ビットマスクの値]になるからです。
次の項目でその計算している様子を書いてみました。
計算を並べてみるとなんとなく雰囲気で見えてくる
アンケートの選択肢(複数選択可)として、XとYとZの3つがあり、Aさんは、ZとYを選択しています。
選択肢の状態をZYXの順に並べるとすると、110(2進数) となり、Aさんの選択状態は、10進数で6という数値で表現できます。
なので、例えば、データベースには6という数値が入っています。
Aさんの選択状態をプログラムで調べる時は、以下の計算処理をすることになります。
[X]を選択しているかをチェック
110…6(10進数)
&
001…1(10進数) ←Xの桁のみ1のビットマスク
=
000…0(10進数)
0なので、Xを非選択。(と後のプログラム処理を書く)
[Y]を選択しているかをチェック
110…6(10進数)
&
010…2(10進数) ←Yの桁のみ1のビットマスク
=
010…2(10進数)
2(0以外)なので、Yを選択。(と後のプログラム処理を書く)
[Z]を選択しているかをチェック
110…6(10進数)
&
100…4(10進数) ←Zの桁のみ1のビットマスク
=
100…4(10進数)
4(0以外)なので、Zを選択。(と後のプログラム処理を書く)
結果、Aさんの「6」は[Y][Z]の計算結果が0ではないので、[Y]と[Z]を選択していると判定し、後のプログラム処理を行う。
javascriptで簡単に書いてみます
var a=6,i,f,b=['X','Y','Z'],s='Aさんは';
for(i=0;i<3;i++){
f=Math.pow(2,i);
s+='【'+b[i]+'を選択して';
s+=(a&f)?'いる':'いない';
s+='】';
}
以下、出力部分は省略
テスト
&の計算結果を個別表示
テスト結果表示
アンケートフォームネタの確認テスト用プログラム
前回記事のアンケート複数選択可のチェックボックスの選択状態を示す10進数値とその値から選択状態をチェックする確認テスト用jsプログラムです。
ビットマスクとの&演算で選択しているかどうか判定するアイデア
zyx
&
001 (ビットマスク)
=
000 or 001
ビットマスクの1のある桁以外は0になり、1のある桁は相手のxが0か1なので、結果も0か1、
つまり計算結果は、000 か 001(ビットマスクの値) のどちらかになる
なので、その判定結果の値が「0」なら選択していない、[0以外]なら選択しているとして 後のプログラム処理を作ることで、「ビット演算なんて何に使えるんだ?」(5&3=1なら意味不明)という感想だった仕様が、選択状態を表している数値とビットマスクで &演算すると、各桁の選択状態を判定するためのアイデアとして使える、というものになりました。
10進数の7を2進数にすると、111なので、それを複数を選択している状態と置き換えて考えると、人間なら一目でなんとなく理解することができるけど、コンピュータは単にプログラム通りに計算しているだけなので、計算結果を使って人間が考えた後の処理を指定してあげることで、意味あるアウトプットにすることができる、という例として紹介してみました。
ということで、この前回と今回の記事で、複数の選択状態を10進数数値1個で表現したり、その値から何が選択されているかを調べる方法を紹介してみました
何に使うものなのかを調べるだけではなくて、意味を理解したり別の視点を持って調べてみたり、何かと組み合わせてみることで、いろんな応用が考えられ、どこかで使われている、または、本には書いてないようなアイデアの元になる可能性があるというのもアイデア考察のネタ本で書いてあったりするようなことなのですが、特にプログラムでは、その人専用視点(これまで生きてきた人生経験でのみ見知った世界観にしかない知識)だけではなくて、数学的だったりコンピュータの概念的な知識も、調べてみると案外面白い発見や新たな視点の元ネタになるかもしれないですね~、というのが今回テーマでした。
WEBで仕事する場合、こういうアイデアのベースにあるコンピュータ数学をネタとして持っておくと、楽ができたり面白いものが発明できるかもしれません。
興味があれば、アルゴリズム関連なども、調べてみると、小難しそうにみえる基礎的なプログラムネタの中に、新たなオリジナルプログラムアイデアが浮かぶようなものがあったりする可能性もあるかもしれないのでは?などと思ったりします。
とりあえず、お疲れさまでした。