社内で先輩エンジニアから教えてもらったビット演算に関する考え方、まだしっかり
理解できていないけど、保管しておきたいので。
「フラグを検知する仕組み」と思ってください。
詳しく知りたかったらググってください。いっぱいあるので。
上記の通りフラグを検知できるので、1カラムに保管したデータに対して以下の判定をすることができます。
・「A」があるか?(無いか?)
・「B」があるか?(無いか?)
・「AとB」の両方があるか?(無いか?)
上記の機能によりnのデータを1カラムで表すことができます。
さらに、SQLのWHERE句でも上記の判定をできるので、検索等においても利用できるので大変便利。
但しビットなどといってもデータは単なる「正の整数」(int)なので、32bitで表現できる整数の最大値は「4294967295」になります。
64bitだともっと扱えますがどちらにしても制限がある事には変わりないので32bitの最大値で考えた方が無難です。
(例えばMySQLが64bitバージョンを利用してもrubyが32bitで実行されるとMySQLからデータ取得した時に桁溢れを起こします。
環境に依存するコーディングや設計は極力避けましょう)
そうなると表現できる種類は32通りになります。
よって、選択肢が(増えても)30以下ならビットで表すのも方法の1つ。
ちなみに10進数だと人が目で見て分かり辛いので、プログラム上は通常16進で表記します。
以下はよく使う簡単な例です。
●定義
※本当は先日に記載の通り定数化&配列定義して利用する。
nil 未入力
0x00000 特に無し
0x00001 総合感冒薬
0x00002 咳止め
0x00004 鼻水止め
0x00008 熱冷まし・痛み止め
0x00010 痰を出やすくする薬
0x00020 抗生剤
0x00040 インフルエンザの薬
0x00080 喘息の薬
●データ
0x00038 熱冷まし・痛み止め、痰を出やすくする薬、抗生剤
●SQLの例
例)「痰を出やすくする薬」を含むのを取得
SELECT * FROM interview_sheets WHERE (medecine_requerst & 0x00010)<>0
例)「熱冷まし・痛み止め」「痰を出やすくする薬」の両方を含むものを取得
SELECT * FROM interview_sheets WHERE (medecine_requerst & 0x00018)=0x00018
●rubyの例
例)「痰を出やすくする薬」を含むのを取得
if (medecine_requerst & 0x00010) != 0
end
例)「熱冷まし・痛み止め」「痰を出やすくする薬」を変数にセット
medecine_requerst = 0x00008|0x00010
「単純に10進数の0~15を1桁で表す(0123456789ABCDEF)方法」だけで充分です。
換算方法は不要です(必要になったら変換サイトでOK)。
16進数は先頭に「0x」を付けるというルールになっています。
(桁数は「人間の見た目」の為に0パディングしてます。なくても良いです)
16進数 10進数
0x0001 1
0x0002 2
0x0003 3
0x0004 4
0x0005 5
0x0006 6
0x0007 7
0x0008 8
0x0009 9
0x000A 10
0x000B 11
0x000C 12
0x000D 13
0x000E 14
0x000F 15
0x0010 16 ※Fまで来たので桁を繰り上げる。
0x0011 17
昨日の例の定義で、0x001、0x002、0x004、0x008と「飛んで」いるのはビット演算の為です。
0は「0」です。
1はフラグとして利用します。
2はフラグとして利用します。その前に1が登場しましたが数字1個では演算ができませんので2もフラグとして利用します。
3は、その前に登場した1と2の合計が3になるので、3をフラグとして利用すると、1+2を表しているのか、3というフラグを表しているのか区別が出来ません。よってフラグとしては利用しません。
4はフラグとして利用します。3はフラグではない(1+2を表している)ので他に演算するフラグが無い為フラグとして利用します。
、、、を繰り返すと以下のようになります。
16進数 10進数
0x0001 1
0x0002 2
0x0003 3 =1+2
0x0004 4
0x0005 5 =2+3
0x0006 6 =2+4
0x0007 7 =1+2+4
0x0008 8
0x0009 9 =1+8
0x000A 10 =2+8
0x000B 11 =1+2+8
0x000C 12 =4+8
0x000D 13 =1+4+8
0x000E 14 =2+4+8
0x000F 15 =1+2+4+8
0x0010 16
0x0011 17 =16+1
で、上記を繰り返しながら10進数が32bitのintの最大値の4294967295になるのは、
16進数で表すと0xFFFFFFFFになります。
この時「フラグ」として利用できる数が32個になります。
16進数 10進数
0x0001 1
0x0002 2
0x0004 4
0x0008 8
0x0010 16
0x0020 32
0x0040 64
0x0080 128
0x0100 256
0x0200 512
0x0400 1024
0x0800 2048
...
1248を桁を変えながら繰り返していくので目で見て分かり易いですね。
同じ事を16進と10進で表してみます。
(0x0110 & 0x0010)<>0 → 0x0110に0x0010が含まれているか?→うん。入ってるね。
(272 & 16)<>0 → 272に16が含まれているか?→は?何言ってんの?となる。