第9回は、VBAで、論理演算子を使ったビット演算について、解説したいと思います。
ビット演算は、2進数で考えなければいけませんので、馴染みのない方は、難しい印象を受けるかもしれませんが、実は非常に単純な理論ですので、そのあたりを今回、解説できればと思います。ビットの演算に先立って、VBAで利用できる論理演算子と、その演算の真理値表を紹介します。
このようにVBAで利用できる論理演算子には、And、Or、Xor、Eqv、Imp、Notがあります。よくプログラムで使用するのは、And、Or、Xor、Not、あたりでしょうか。私の経験上、Eqv、Impについては、ほとんど使用する機会はないように思います。今回は、And、Or、Notの演算子に絞り、例を用いて説明していきます。
サンプルファイルのダウンロード
And演算、Or演算及び、Not演算について、数値を使って説明したいと思います。
まず、論理積(And)についてですが、簡単な例を示すと以下のようになります。
これは、100(10進数)と170(10進数)の論理積(And)を求めたもので、その時の値は32(10進数)となります。
この例を、実際にプログラムで実装したものが以下となり、サンプルファイルの【論理積(And)】ボタンを押下することで、実行できます。
'論理積(And演算)
Private Sub CBtnAnd_Click()
Dim A As Byte
Dim B As Byte
Dim C As Byte
A = 100
B = 170
C = A And B
Debug.Print "A = " & A & vbTab & "(2進:" & BIN_STR(A) & ")"
Debug.Print "B = " & B & vbTab & "(2進:" & BIN_STR(B) & ")"
Debug.Print "C = " & C & vbTab & "(2進:" & BIN_STR(C) & ")"
End Sub
実際に、【論理積(And)】ボタンを押した時の、出力結果が以下です。
上の真理値表での演算結果 32(2進:00100000) と一致することが確認できます。
A = 100 (2進:01100100)
B = 170 (2進:10101010)
C = 32 (2進:00100000)
次に、論理和(Or)の例ですが、以下のようになります。
この論理和の例を、プログラムで実装したものが以下で、これは、サンプルファイルの【論理和(Or)】ボタンを押下することで、実行できます。
'論理積(Or演算)
Private Sub CBtnOr_Click()
Dim A As Byte
Dim B As Byte
Dim C As Byte
A = 100
B = 170
C = A Or B
Debug.Print "A = " & A & vbTab & "(2進:" & BIN_STR(A) & ")"
Debug.Print "B = " & B & vbTab & "(2進:" & BIN_STR(B) & ")"
Debug.Print "C = " & C & vbTab & "(2進:" & BIN_STR(C) & ")"
End Sub
【論理和(Or)】ボタンを押した時の、出力結果が以下です。
上の真理値表での演算結果 238(2進:11101110) と一致することが確認できます。
A = 100 (2進:01100100)
B = 170 (2進:10101010)
C = 238 (2進:11101110)
続いて、論理否定演算Notを、例を用いて説明したいと思います。
これは、170(2進:10101010)の論理否定(Not)を求めたもので、その時の値は85(2進:01010101)となります。
この例を、実際にプログラムで実装したものが以下となり、サンプルファイルの【論理否定(Not)】ボタンを押下することで、実行できます。
'論理否定(Not演算)
Private Sub CBtnNot_Click()
Dim A As Byte
Dim B As Byte
A = 170
B = Not A
Debug.Print "A = " & A & vbTab & "(2進:" & BIN_STR(A) & ")"
Debug.Print "B = " & B & vbTab & "(2進:" & BIN_STR(B) & ")"
End Sub
実際に、【論理否定(Not)】ボタンを押した時の、出力結果が以下です。
上の真理値表を使った演算結果 85(2進:01010101) と一致することが確認できます。
A = 170 (2進:10101010)
B = 85 (2進:01010101)
上記で、論理積(And)、論理和(Or)、論理否定(Not)の演算について簡単に説明しましたが、次は、プログラムにおける、これらの論理演算の具体的な使い方を説明したいと思います。
プログラムで、意図したビットを立てた(0→1)データを作成するときは、論理和(Or)を使用します。
その際に、以下の早見表があると便利ですので、参考にしてください。これは、あるビットを立てた場合の、16進値を探すときに使用します。立てるビット桁を大きくしていくと、16進値は、1、2、4、8を繰り返しながら、桁が増えていきます
<16進値早見表>
例えば、1ビット目、3ビット目、5ビット目を立てたデータを作るとします。各ビットの値を立てた時の、16進値を早見表で確認すると、それぞれ、&H01、&H04、&H10となっています。この値をすべて、Or演算子で連結すると、1、3、5ビット目が立った値が作成できます。
値 = &H01 Or &H04 Or &H10
この値を真理値表に基づいて計算すると、以下のように値21(2進:00010101)となります。
これを、プログラムで実装すると以下となり、このプログラムは、サンプルファイルの【1、3、5ビット目を立てる】ボタンを押すことで実行可能です。
'1、3、5ビット目を立てます。
Private Sub CBtnBits_Click()
Dim A As Byte
A = &H1 Or &H4 Or &H10
Debug.Print "A = " & A & vbTab & "(2進:" & BIN_STR(A) & ")"
End Sub
実行結果は以下となり、先に、真理値表を基にして算出した値21と合致することが分かります。
A = 21 (2進:00010101)
逆に、あるデータの特定のビットを落としたい場合は、And演算子とNot演算子を使用します。手順としては、まず、落としたいビットを組み合わせた論理和値を算出し、その値Not演算子で反転させます。次に、この値と、ビットを落としたい値との論理積(And)を取ります。これにより、落としたい値の、対象ビットが0となるはずです。
それでは、先ほど作成したデータ21(2進:00010101)の、1、3ビット目のデータを落としてみましょう。
値 = 21 And Not(&H01 Or &H04)
これを、プログラムで実装すると以下となり、このプログラムは、サンプルファイルの【1、3、5ビット目を落とす】ボタンを押すことで実行可能です。
'1、3ビット目を落とします。
Private Sub CBtnBitsOff_Click()
Dim A As Byte
Dim B As Byte
Dim C As Byte
A = 21
B = &H1 Or &H4
B = Not B
C = A And B
Debug.Print "A = " & A & vbTab & "(2進:" & BIN_STR(A) & ")"
Debug.Print "B = " & B & vbTab & "(2進:" & BIN_STR(B) & ")"
Debug.Print "C = " & C & vbTab & "(2進:" & BIN_STR(C) & ")"
End Sub
実行結果は以下となり、先に、真理値表を基にして算出した値16と合致することが確認できました。
A = 21 (2進:00010101)
B = 250 (2進:11111010)
C = 16 (2進:00010000)
プログラムであるデータの特定のビットが、立っているかどうかをチェックするには、論理演算子の論理積(And)を使用します。例えば、8ビット目が立っているかどうかをチェックするには、&H80(早見表の8ビット目)と論理積(And)を取ります。この時に演算結果が、0(False)でなければ、8ビット目が立っているということになります。
このことを確認するためのプログラムが以下となります。サンプルファイルの【ビットのチェック(単一)】ボタンを押してみてください。
'ビットのチェック(単一)
Private Sub CBtnChckBitOne_Click()
Dim A As Byte
Dim B As Byte
Dim C As Byte
A = 85
B = 170
C = &H80
Debug.Print "A = " & A & vbTab & "(2進:" & BIN_STR(A) & ")"
Debug.Print "B = " & B & vbTab & "(2進:" & BIN_STR(B) & ")"
Debug.Print "C = " & C & vbTab & "(2進:" & BIN_STR(C) & ")"
If A And C Then
Debug.Print "Aは、8ビット目が立っています。"
Else
Debug.Print "Aは、8ビット目が立っていません。"
End If
If B And C Then
Debug.Print "Bは、8ビット目が立っています。"
Else
Debug.Print "Bは、8ビット目が立っていません。"
End If
End Sub
実行結果は以下となり、ビットのチェックが出来ていることが分かります。
A = 85 (2進:01010101)
B = 170 (2進:10101010)
C = 128 (2進:10000000)
Aは、8ビット目が立っていません。
Bは、8ビット目が立っています。
今度は、1つのビットだけでなく、複数のビットのチェックを行ってみたいと思います。チェック値は、チェックしたいビットを1にした値の論理和(Or)で作成します。この値と論理積Andを取ることで、複数ビットのチェックが可能になります。
チェックの仕方によって、プログラムの実装が少し異なってきますの注意が必要です。複数ビットの全てが、立っているかどうかを、チェックしたいのであれば、論理積Andの結果が、チェックした値と同じかどうかをチェックします。複数ビットのいずれかが立っているかどうかを、チェックしたいのであれば、演算結果が単純に、0かそうでないかで判定します。
チェック方法を簡潔に纏めると以下となります。
以下のサンプルプログラムで上記が確認できます。少し、冗長的なプログラムになってしまいましたが、【ビットのチェック(複数)】ボタンを押下してみてください。
'ビットのチェック(複数)
Private Sub CBtnChckBitMulti_Click()
Dim A As Byte
Dim B As Byte
Dim C As Byte
Dim D As Byte
A = 85
B = 170
C = &H80 Or &H40
D = &H80 Or &H20
Debug.Print "A = " & A & vbTab & "(2進:" & BIN_STR(A) & ")"
Debug.Print "B = " & B & vbTab & "(2進:" & BIN_STR(B) & ")"
Debug.Print "C = " & C & vbTab & "(2進:" & BIN_STR(C) & ")"
Debug.Print "D = " & D & vbTab & "(2進:" & BIN_STR(D) & ")"
'*** A ***
'* C:6、8ビットが1*
If (A And C) = C Then
Debug.Print "Aは、チェックしたCの、全てのビットが立っています。"
ElseIf A And C Then
Debug.Print "Aは、チェックしたCの、いずれかのビットが立っています。"
Else
Debug.Print "Aは、チェックしたCの、ビットは立っていません。"
End If
'* D:7、8ビットが1 *
If (A And D) = D Then
Debug.Print "Aは、チェックしたDの、全てのビットが立っています。"
ElseIf A And D Then
Debug.Print "Aは、チェックしたDの、いずれかのビットが立っています。"
Else
Debug.Print "Aは、チェックしたDの、ビットは立っていません。"
End If
'*** B ***
'* C:6、8ビットが1*
If (B And C) = C Then
Debug.Print "Bは、チェックしたCの、全てのビットが立っています。"
ElseIf B And C Then
Debug.Print "Bは、チェックしたCの、いずれかのビットが立っています。"
Else
Debug.Print "Bは、チェックしたCの、ビットは立っていません。"
End If
'* D:7、8ビットが1 *
If (B And D) = D Then
Debug.Print "Bは、チェックしたDの、全てのビットが立っています。"
ElseIf B And D Then
Debug.Print "Bは、チェックしたDの、いずれかのビットが立っています。"
Else
Debug.Print "Bは、チェックしたDの、ビットは立っていません。"
End If
End Sub
実行結果は以下となり、複数のビットのチェック動作が確認できました。
A = 85 (2進:01010101)
B = 170 (2進:10101010)
C = 192 (2進:11000000)
D = 160 (2進:10100000)
Aは、チェックしたCの、いずれかのビットが立っています。
Aは、チェックしたDの、ビットは立っていません。
Bは、チェックしたCの、いずれかのビットが立っています。
Bは、チェックしたDの、全てのビットが立っています。
今回の豆知識は、以上で終了したいと思います。最初にも述べたのですが、ビット演算と聞くと、なんだか難しそうというイメージを持ちそうなのですが、単純な0と1の組合せによる演算ということが理解できれば、意外と、そうでもないのでは、ないでしょうか。もう少し、このビット演算について、お話したいことがありますので、それは、次回に持ち越したいと思います。
以下から、今回の豆知識で紹介した内容のエクセルファイルがダウンロードできます。
サンプルのダウンロード
2、10、16進値の相互変換はWindows標準アプリの電卓を利用すると簡単です。2のn乗を使った理論式を説明する、教科書本なども多くありますが、私は、この式を使って求めたことはありません。電卓を使いましょう。
スタートメニューから電卓を起動します。
※スタートメニューの中から、電卓のアイコンをクリックしてもOKです。
電卓の【メニュー】-【表示】-【プログラマ】を選択します。以下の各進数を切り替えることで、変換できます。数値のコピペ機能も使えます。
ご意見・ご要望等ありましたら、画面最下部のメールアドレスまでご連絡ください。