最初に断っておきますが、この記事は半分ネタです。
あえて、面倒くさいことしてます。
私がやりたかっただけです。
基本に則って2進表示を求めたい方は、
とか、して下さい。
但し、10進数の2進数表示した文字列を取得する関数は、探せば結構出てきますが
大体は、2で割って余りを求めて・・・
でも、負の数まで考慮されているものはほとんど無いようです。
私が見つけた1件でも、値によってはオーバーフローして、十分な検証はされていないようでした。
WorksheetFunction.Dec2Bin は、
数値 < -512 または数値 > 511 の場合、エラー値 #NUM! が返されます。
WorksheetFunction.Dec2Bin メソッド (Excel)
と、あまり使い物にならないかもしれません。
コード その1
割り算を使った方法は、上位の桁から処理していくが、割り算を使用しないということは、その逆で、下位から処理を行っていきます。
2^0 の桁 から Integerなら、2^15 の桁に向かって処理を行います。
流れとしては
最初に、変換したいデータと 1 ( = 2^0 )のAnd を取る。
奇数の場合、2^0の桁は 1 なので
1 And 1 ===> 1
となり、
偶数の場合、2^0の桁は 0 なので
0 And 1 ===> 0
となる。
And を取った結果が、2^0 の桁の値となる。
これを桁を、2^1の桁、2^2の桁と、上位方向にずらして繰り返していく。
「And演算子って何?」とか、
「なんで数値同士でAndなの?」とか
「A And B って、A かつ B じゃないの?」
という方は、以下のリンクをどうぞ。
(解説の下の方に書いてあります。)
docs.microsoft.com
以下が、その処理を行うコードです。
但し、Integer も Long も符号付き故に、大抵は、最上位bitでの処理に苦しみます。(多分、私だけではないと思う。)
結局は、それを回避するためにゴチャゴチャと・・・
Public Function Dec2Bin16(ByVal iDecValue As Integer) As String
Dim sBin As String
Dim iBitMask As Integer
Dim iMask As Integer
Dim lBitIndexR As Long
Const BIT_ON_FULL As Integer = &HFFFF
Const BIT_ON_TOP_BIT_ONLY As Integer = &H8000
Const BIT_ON_SECONT_BIT_ONLY As Integer = &H4000
Const BIT_LENGTH As Long = 16
If iDecValue = 0 Then
Dec2Bin16 = String$(BIT_LENGTH, "0")
Exit Function
ElseIf iDecValue < 0 Then
If iDecValue = -1 Then
Dec2Bin16 = String$(BIT_LENGTH, "1")
Exit Function
ElseIf iDecValue = BIT_ON_TOP_BIT_ONLY Then
Dec2Bin16 = "1" & String$(BIT_LENGTH - 1, "0")
Exit Function
End If
End If
sBin = String$(BIT_LENGTH, "0")
iBitMask = 1
lBitIndexR = 1
iMask = BIT_ON_FULL
Do Until (iDecValue And iMask) = 0
If (iDecValue And iBitMask) = iBitMask Then
Mid$(sBin, BIT_LENGTH - lBitIndexR + 1, 1) = "1"
End If
iMask = iMask And (Not iBitMask)
lBitIndexR = lBitIndexR + 1
If (iBitMask And BIT_ON_SECONT_BIT_ONLY) = 0 Then
iBitMask = iBitMask * 2
Else
Exit Do
End If
Loop
If (iDecValue And BIT_ON_TOP_BIT_ONLY) = BIT_ON_TOP_BIT_ONLY Then
Mid$(sBin, 1, 1) = "1"
End If
Dec2Bin16 = sBin
End Function
Public Function Dec2Bin32(ByVal lDecValue As Long) As String
Dim sBin As String
Dim lBitMask As Long
Dim lMask As Long
Dim lBitIndexR As Long
Const BIT_ON_FULL As Long = &HFFFFFFFF
Const BIT_ON_TOP_BIT_ONLY As Long = &H80000000
Const BIT_ON_SECONT_BIT_ONLY As Long = &H40000000
Const BIT_LENGTH As Long = 32
If lDecValue = 0 Then
Dec2Bin32 = String$(BIT_LENGTH, "0")
Exit Function
ElseIf lDecValue < 0 Then
If lDecValue = -1 Then
Dec2Bin32 = String$(BIT_LENGTH, "1")
Exit Function
ElseIf lDecValue = BIT_ON_TOP_BIT_ONLY Then
Dec2Bin32 = "1" & String$(BIT_LENGTH - 1, "0")
Exit Function
End If
End If
sBin = String$(BIT_LENGTH, "0")
lBitMask = 1
lBitIndexR = 1
lMask = BIT_ON_FULL
Do Until (lDecValue And lMask) = 0
If (lDecValue And lBitMask) = lBitMask Then
Mid$(sBin, BIT_LENGTH - lBitIndexR + 1, 1) = "1"
End If
lMask = lMask And (Not lBitMask)
lBitIndexR = lBitIndexR + 1
If (lBitMask And BIT_ON_SECONT_BIT_ONLY) = 0 Then
lBitMask = lBitMask * 2
Else
Exit Do
End If
Loop
If (lDecValue And BIT_ON_TOP_BIT_ONLY) = BIT_ON_TOP_BIT_ONLY Then
Mid$(sBin, 1, 1) = "1"
End If
Dec2Bin32 = sBin
End Function
Long(32bit 符号付き)版のコードは、必要最小限にコメントを省いているので、コメントが必要な方は、Integer(16bit 符号付き)版のコメントを参照して下さい。
微妙に違うところはありますが、ほぼ分かると思います。
コード その2
VBAで、エンディアンの変換をやろうとしたら、やっぱりハマった - 空腹おやじのログと備忘録 のおまけで書いたコードと似たような手法。
最初に変換したい値を16進の文字列に変換して、16進数1文字につき、2進数4文字に変換していく。
値の正負を意識する必要がない。
オーバーフローの心配もなく、手っ取り早い。
お気軽に使いたいなら、こちらの方がおすすめ。
Integer(16bit)版のみ掲載
Long(32bit)版が欲しい方は、適当にアレンジして下さい。そんなに難しくはないと思いますので。
Public Function Dec2BinS16(ByVal iDecValue As Integer) As String
Dim sHex As String
Dim sBin As String
Dim i As Long
Static sHB(15) As String
Static isInitialized As Boolean
If isInitialized = False Then
sHB(0) = "0000"
sHB(1) = "0001"
sHB(2) = "0010"
sHB(3) = "0011"
sHB(4) = "0100"
sHB(5) = "0101"
sHB(6) = "0110"
sHB(7) = "0111"
sHB(8) = "1000"
sHB(9) = "1001"
sHB(10) = "1010"
sHB(11) = "1011"
sHB(12) = "1100"
sHB(13) = "1101"
sHB(14) = "1110"
sHB(15) = "1111"
isInitialized = True
End If
sHex = Right$(String$(3, "0") & Hex(iDecValue), 4)
sBin = String$(16, "0")
For i = 0 To 3
Mid$(sBin, i * 4 + 1, 4) = sHB(CInt("&H" & Mid$(sHex, i + 1, 1)))
Next i
Dec2BinS16 = sBin
End Function
あぁ、今日も自己満足の世界に・・・