こんにちは、Ryoです。
今回機会があったので、10進数の小数点有無対応(符号なし)で2進数/16進数に変換するVBAサンプルコードを作成しています。インプットボックスに数値入力し計算結果をイミディエイトウィンドウに表示する簡易的なものですが、その内容について書いていきます。
1.サンプル概要
10進数の整数、及び小数点に対応できますので起動後に表示されるInputBoxに数値を入力します。この時に数値以外や符号(-など)が含まれていると受け付けませんので、正常な数値が入力されるまでループ表示させています。
数値を入力してOKボタンを押すと、以下画像のようにイミディエイトウィンドウに計算結果として2進数と16進数それぞれの変換値を表示します。
小数についても整数部と小数部をそれぞれ計算して変換し、結果を表示します。
桁合わせとしては整数部をmin「8bit」、小数部をmin「4bit」とし全体では計算結果から「8bit/16bit/24bit/32bit/64bit」の何れかを自動的に判定して表示する形としています。
ちなみに以前16進数(符号有無、小数点対応)を2進数/10進数に変換するサンプルコードも作成しているので、ご参考までに。
2.サンプルコード
構成としてはメイン処理を行うプロシージャ「Sample1()」、Functionプロシージャとして16進数変換処理を行う「smp2」と桁合わせ処理を行う「smp3」となっています。
◆メイン処理:Sub Sample1()
Sub Sample1() '※※※10進数(符号なし)⇒2進数/16進数へ変換※※※ Dim ide As Boolean Dim ans, Dnum, quot As Variant Dim num As Long Dim flg, s, i, scnt, dcnt As Integer Dim bin_n, Dta, dec_bin As String Dim cnt, cntA As Variant ide = False '変換元の数値入力用インプットボックス表示 '数値以外の入力は受け付けずループするが、 '「×」や「キャンセルボタン」で終了 Do ans = InputBox("数値を入力してください。") If StrPtr(ans) = 0 Then Exit Sub '符号付きには非対応の為、含まれていないことを確認 'StrConv関数を利用して入力記号を半角に統一 If InStr(StrConv(ans, vbNarrow), "-") = 0 _ And IsNumeric(ans) Then ide = True Loop Until ide = True 'イミディエイトウィンドウへの入力元値を表示 Debug.Print "入力値: " & ans '************************* '整数/小数の区分けと識別 '************************* '入力値に"."が含まれているかどうかを判定 If InStr(ans, ".") <> 0 Then 'コンマが含まれていれば「整数部」=num、 '「小数部」=Dnumにそれぞれ分ける 'CDec関数を利用することで誤差を防ぐ num = CDec(Fix(ans)) Dnum = CDec(ans) - CDec(Fix(ans)) Else 'コンマなしであれば整数のみと判定する num = ans flg = 1 End If '元値の整数部が「0」である場合の処理 Select Case num Case Is = 0 bin_n = "0" cnt = 1 End Select '************************* '整数部の10進数⇒2進数/16進数変換 '************************* Do While num <> 0 '元値を2で割り、商を求める quot = num \ 2 '2進数表記の視認性向上を目的として4bit間隔で半角スペース If cnt <> "" And cnt Mod 4 = 0 Then bin_n = bin_n + Space(1) '2で割った際の余り=2進数 bin_n = bin_n + CStr(num Mod 2) '次計算用として変数numへ商を代入 num = quot 'ビット数のカウント用 cnt = cnt + 1 Loop '桁合わせ試算用Functionプロシージャ(smp3)を実行 If cnt Mod 8 <> 0 Then cntA = smp3(cnt) '視認性向上の為の半角スペース追加 If cnt >= 0 And cnt <> "" And cnt Mod 4 = 0 Then _ bin_n = bin_n + Space(1) '桁合わせ必要数(=cntA)に応じて繰り返し処理を実行 For i = 1 To cntA bin_n = bin_n + "0" '桁不足分”0”を追加 If cntA <> i And (cnt + i) Mod 4 = 0 Then _ bin_n = bin_n + Space(1) Next i End If '元値が整数のみ(flg=1)であれば変換した2進数と16進数を 'イミディエイトウィンドウで表示 If flg = 1 Then '上で計算して格納した2進数は逆順となっているので、 'StrReverse関数を利用して並びを反転する Debug.Print "2進数: " & StrReverse(bin_n) '16進数変換用Functionプロシージャへの引渡し用として '変数Dtaに格納する Dta = StrReverse(bin_n) '16進数変換処理(smp2)を実行しイミディエイト 'ウィンドウへ表示し終了する Debug.Print "16進数: " & smp2(Dta) & vbLf Exit Sub End If '************************* '小数部の10進数⇒2進数/16進数変換 '************************* 'ここまでの処理で完了している整数部の文字数をカウントする '(視認性のために設けた半角スペースを除去してカウント) s = Len(Replace(bin_n, " ", "")) 'カウントした整数部の文字数に応じて '小数部の表示桁数を設定(主に32bit表示) Select Case s Case Is = 32 scnt = 32 Case Is < 32 scnt = 32 - s End Select dcnt = 1 '小数部を2進数に設定桁数分変換する Do While dcnt <= scnt '10進数の小数部を2倍して商を求める '商の小数部を繰り返し2倍することで2進数を計算する Dnum = (Dnum - Fix(Dnum)) * 2 dec_bin = dec_bin + CStr(Fix(Dnum)) If dcnt Mod 4 = 0 Then '視認性向上のための半角スペース追加 dec_bin = dec_bin + Space(1) '商の小数部が”0”となる場合はループ強制終了 If Dnum - Fix(Dnum) = 0 Then Exit Do End If dcnt = dcnt + 1 Loop '整数部と小数部の2進数変換文字列数をカウントする cnt = Len(Replace(bin_n, " ", "")) + _ Len(Replace(dec_bin, " ", "")) '総桁数が8/16/24/32/64bit以外であれば桁合わせ処理実行 If cnt Mod 8 <> 0 Then cntA = smp3(cnt) bin_n = bin_n + Space(1) cntA = cntA + (cntA \ 4 - 1) For i = 1 To cntA If i Mod 5 = 0 Then bin_n = bin_n + Space(1) Else bin_n = bin_n + "0" End If Next i End If '桁合わせ処理完了後、整数部/カンマ/小数部を結合する Dta = StrReverse(bin_n) & " . " & dec_bin 'イミディエイトウィンドウに表示する Debug.Print "2進数: " & Dta '16進数変換用プロシージャにて処理を行いウィンドウに表示 Debug.Print "16進数: " & smp2(Dta) & vbLf End Sub
処理内容などはコード内コメントにも記述しているので詳細を割愛しますが、主な点について書いていきます。
先ずメイン処理のSample1()ですが、小数部の計算を行う際に誤差影響をうけないよう最初の入力値を処理する際にCDec関数を利用しています。ここを通常のDouble型等で計算を行うと(例)4.12-4を計算しても0.12とならずに0.11999987・・・のようになることもあり、この状態で計算処理を行うと結果に影響が出ることもありますから留意しておく必要があります。
またCDec関数を使用する場合、型はVariantになりますのでサンプルコード内で使用する対象の変数について宣言しておきます。
次は10進数を2進数に変換していきますので小数部有無等を判定し、それぞれの変換処理として整数部は元値を2で割り商と余りを求めて2進数を算出、小数部は10進数の小数部を繰り返し2倍して商を求めて2進数を算出しています。
この時に整数部の2進数は処理として格納された文字列の逆順になりますので、StrReverse関数を利用して反転させると便利です。
構文:StrReverse(expression)
引数expressionには逆順(反転)したい文字列を指定しますので、サンプルコードでは変数bin_n(整数部の2進数変換格納用の変数)になります。
後は16進数の変換や桁合わせ処理を各ファンクションプロシージャで実行し、最終的な計算結果をイミディエイトウインドウに出力して処理完了となります。
◆16進数変換処理:Function smp2
Function smp2(ByVal Dta As String) As String '※※2進数⇒16進数変換処理を行う※※ Dim TrDta, Db As String Dim i As Integer '受け渡された2進数文字列から半角スペースを除去 Dta = Replace(Dta, " ", "") '2進数文字列データ数分繰り返し処理を実行 For i = 1 To Len(Dta) '文字列内にコンマがある場合は変換したデータへ 'コンマを連結し、次ループ処理を行う If Mid(Dta, i, 1) = "." Then TrDta = TrDta + "." GoTo Continue Else '文字列左端から1文字ずつ順に抜取り連結(変数Db) Db = Db + Mid(Dta, i, 1) End If '抜取り文字列数が4つ(4bit分)となる毎に以下Caseの '該当内容に応じて16進数文字列を変数TrDtaに格納 If Len(Db) = 4 Then Select Case Db Case Is = "0000" TrDta = TrDta + "0" Case Is = "0001" TrDta = TrDta + "1" Case Is = "0010" TrDta = TrDta + "2" Case Is = "0011" TrDta = TrDta + "3" Case Is = "0100" TrDta = TrDta + "4" Case Is = "0101" TrDta = TrDta + "5" Case Is = "0110" TrDta = TrDta + "6" Case Is = "0111" TrDta = TrDta + "7" Case Is = "1000" TrDta = TrDta + "8" Case Is = "1001" TrDta = TrDta + "9" Case Is = "1010" TrDta = TrDta + "A" Case Is = "1011" TrDta = TrDta + "B" Case Is = "1100" TrDta = TrDta + "C" Case Is = "1101" TrDta = TrDta + "D" Case Is = "1110" TrDta = TrDta + "E" Case Is = "1111" TrDta = TrDta + "F" End Select Db = "" End If Continue: Next i '処理完了後、実行元プロシージャへ値を返す smp2 = TrDta End Function
メイン処理を行うSample1()から2進数(変数Dta)を受け取り、その文字列を4bit単位で抜き取ってSelect Case文の処理することにより、適した16進数文字列に変換する処理になります。
受け取った2進数文字列は視認性を向上させるために4bit毎に半角スペースを入れているので、それをReplace関数を用いて除去しています。
Dta = Replace(Dta, ” “, “”)
後は文字列数分の繰り返し処理を行いながら4bit単位で16進数文字列に置換しています。
処理完了後、メイン処理のSample1()へ値を返して終了になります。
◆桁合わせ処理:Function smp3
Function smp3(ByVal cnt As Long) As Long '※※桁合わせ処理用※※ Dim lcnt As Long '受け渡された数値を元に桁合わせ必要数を設定 Select Case cnt Case Is < 8 lcnt = 8 - cnt Case Is < 16 lcnt = 16 - cnt Case Is < 24 lcnt = 24 - cnt Case Is < 32 lcnt = 32 - cnt Case Is < 64 lcnt = 64 - cnt End Select '処理完了後、実行元プロシージャへ値を返す smp3 = lcnt End Function
この処理はメイン処理を行うSample1()内に記述しても良いのですが、その場合は記述が重複してしまうのでFunctionプロシージャとしています。
実施内容としては上に書いた通り、整数部をmin8bit、小数部をmin4bitとし全体では計算結果から8bit/16bit/24bit/32bit/64bitの何れかとするよう桁合わせを行う為のものになります。
受け取った値は2進数変換でのbit数になるので、桁合わせする上で不足数を算出して実行元プロシージャに返す簡単な処理になります。
3.まとめ
このようなn進数変換などの計算方法や変換手順などは色々なやり方があると思いますが、以前に投稿した16進数⇒2進数/10進数変換の際と同様で私が思いつくままに書いてみたものになります。
計算結果などは色々なパターンで一通り確認しているので概ね計算できるものと思っていますが、今後自身で使用しながら改めて確認していきます。後は符号付きについても計算できるようにしたいと考えているので、合間見ながらコツコツと作っていこうと思います。
以上、10進数(小数点可/符号なし)を2進数/16進数に変換する内容についてでした!今回の記事が何かの参考になれば幸いです。
Ryo