VBA でビット反転など

自作クラスを作らずにVBAでビット列操作をするためには通常 Long型 (4 byte) を使用する。ただし、Long型の32bitのうち、1bitは符号ビットなので、実質簡単に使えるのは31bitなのだ。

そこで、「bを使用ビット数」とする「ビット反転関数 bturn」は次のようになるかね。

function bturn(x as Long, b as Integer) as Long
  'x : 反転させたい値
  'b : 使うビット数(桁数)
  bturn = x Xor (2 ^ b -1)
End Function
  1. 演算子

VBAでは次のようなビット列演算子が使用できる。それぞれの意味を特に説明する必要は無いだろう。

使用例

Dim a as Long
Dim b as Long
Dim c as Long
a = 2^0     '0 0000000000000000000000000000001 = 1
b = 2^1     '0 0000000000000000000000000000010 = 2
c = a Xor b '0 0000000000000000000000000000011 = 3

気づくと思うけど、ビット反転に相当する「Not」が無い。そこで「ビット反転」をするには、関数を自作する必要があるのです。ここで上記演算子を使ってビット反転するにはどうするか考える。まず、それぞれを論理式で書いてみる。(飛ばしても良い)

  • And :  A \wedge B
  • Or :  A \vee B
  • Xor :  (A \wedge \neg B) \vee (\neg A \wedge B)
  • Eqv :  (A \wedge B) \vee (\neg A \wedge \neg B)
  • Imp :  A \rightarrow B \equiv \neg A \vee B

ここでBをTrueとして考えると次のようになる。

  • And :  A \wedge T \equiv A
  • Or :  A \vee T \equiv T
  • Xor :  (A \wedge \neg T) \vee (\neg A \wedge T) \equiv F \vee \neg A \equiv \neg A
  • Eqv :  (A \wedge T) \vee (\neg A \wedge \neg T) \equiv A \vee F \equiv A
  • Imp :  A \rightarrow T \equiv \neg A \vee T \equiv T

※ EqvとImpは最終的に \neg Aになると、「Not A」と評価されるようす。つまり使えないか、使うとめんどくさいことになりそう。

つまりXorを使えば、 \neg A、Aのビット反転が作れます。
なので、マスクビット(希望するビット数だけTになる値)を用意してXorで反転させればAの希望ビット数のビット反転が手に入るということになります。

ってことで、希望する使用ビット数をまず考えます。ここでは境界問題を包含するために、31 bit より小さい16 bitにしましょう。16 bit のマスク = 16 bit全てが1となります。 2^{16}は二進数で「10000000000000000」(桁数17)です。そこから1を引くと、「01111111111111111」となります。これで16 bit全てが1になる数字が作れますね。

で結果、「nを使用ビット数」とする「ビット反転関数 bturn」は次のようになるかなぁ。

function bturn(x as Long, b as Integer) as Long
  'x : 反転させたい値
  'b : 使うビット数(桁数)
  bturn = x Xor (2 ^ b -1)
End Function