積雲が映像制作したMV『RANGEFINDER』公開中
専門88IO

【C&Python】浮動小数点数のバイト列16進法表記

専門

父親が浮動小数点数を16進数に変換する方法を尋ねてきたので、色々調べてみました。

最終的にC言語とPythonで実装したので、備忘録としてまとめていきます。

父は以下のサイトで浮動小数点数を入力し、Hexadecimalの結果をExcelシートに貼り付ける操作を繰り返したそうです。

IEEE 754 浮動小数点数 コンバーター
Androidアプリの開発、Tips、ニュース、アプリレビュー等を発信しています

しかし、膨大なデータとなると単純作業が多くなり効率が悪いです。そこで要望の通り、まずはExcelのマクロでコンバーターを作成できないか調べてみました。

結果:無理でした。筆者のググり力では見つかりません。

これでは実装できないので、他の言語でEXEファイルを作成し、マクロで標準出力を受け取る方向性で進めていくことにします。

浮動小数点数の内部表現

IEEE754規格に準じているとか。

今回は時間もないので、流し読みで片しました。

以下参考

単精度浮動小数点数 - Wikipedia

型変換の方針

要点だけまとめます。

int, float等の型はバイト列に変換可能(メモリ上にデータを置くので当たり前?)
バイト列自体は元データの型を判別できない
int型は16進数(Hex)に変換可能
ここで、
[float]  ->  [byte]  ->  [int]  ->  [hex]

という指標が立ちました。

Pythonでの16進法表現

structライブラリを利用すれば簡単に実装できます。

f = float(3.14)
b = struct.pack(">f", f)

上のコードで浮動小数点数をバイト列に変換できました。ちなみに2行目の">f"はfloat型(ビックエンディアン)の指定です。

次にこのバイト列をint型として再変換します。

i = struct.unpack(">I", b)[0]

">I"という記述からも察することはできますが、上のコードで再変換できます。戻り値はタプルとなるので[0]を忘れないように。

最後に16進数への変換です。hex()関数を利用しましょう。

h = hex(i)

以上をまとめたのが以下のコードになります。

import struct
import sys

def float2hex(f: float) -> str:
    return hex(struct.unpack('>I', struct.pack('>f', f))[0])

if __name__ == '__main__':
    try:
        print(float2hex(float(sys.argv[1])))
    except ValueError:
        print(sys.argv[1])
    except IndexError:
        print()

先程の記述に加えて、第2引数が存在しない場合のValueErrorと数値でない場合のIndexErrorを拾ってエラー処理をしています。

C言語での16進法表現

Pythonと同じイメージで作成しようとしたらドツボにハマりました。

どうやら、共用体(union)を使えば上手くいくようです。

  1. float型とuint32_t型(符号なし32bit整数型)の共用体を作成
  2. float型の方に数値を代入
  3. uint32_t型で取り出して16進数で表示

共用体はデータをメモリ上で同一の場所に保管するので、メモリ上のバイト列を介して変換を行います。(過程は上の方針とほぼ同じ)

これを基に作成したのが以下のコードです。

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    // 引数がなければエラーで終了
    if (argc == 1)  return -1;

    union {
      float f;
      uint32_t ui;
    } data;

    char *endptr;
    data.f = strtof(argv[1], &endptr);
    // 文字列->浮動小数点数 の変換に失敗した場合、エラーで終了
    if (*endptr != '\0')  return -2;

    // 16進数として出力
    printf("0x%08x", data.ui);

    return 0;
}

こちらも簡単なエラー処理は加えました。(穴はたくさんありそう。)

Excel上でマクロ作成

VBA上での外部コマンド実行及び標準出力の取得は以下のサイトを参考に作成しました。

Office TANAKA - Excel VBA Tips[MS-DOSコマンドの標準出力を取得する]

コードは以下の通りです。

Public Sub float2hex()
  Dim sCmd, Result As String
  Dim Cell As Range
  Dim WS, wExec

  Set WS = CreateObject("WScript.Shell")
  ChDir ThisWorkbook.Path

  For Each Cell In Selection
    If Cell.Value = "" Then
      GoTo Continue
    End If

    sCmd = ".\bin\float2hex.exe" & Str(Cell.Value)
    Set wExec = WS.Exec("%ComSpec% /c " & sCmd)
    Do While wExec.Status = 0
      DoEvents
    Loop

    Result = wExec.StdOut.ReadAll
    Cell.Value = Replace(Result, vbLf, "")

Continue:
  Next Cell
End Sub

上のマクロでは選択セルの数値をC言語で作成したコンバーターを介して16進法表記に変換します。

また、実行するファイルのパスに依存しないようにこのマクロを含むブックからの相対パスでEXEファイルを指定しています。

公開

コード及びブックはGitHubで公開しています。

GitHub - 88IO/float2hex: 浮動小数点数の16進数表現を出力。
浮動小数点数の16進数表現を出力。. Contribute to 88IO/float2hex development by creating an account on GitHub.

方法がすぐに見つからなかったため、EXEファイルも梱包してありますが、あまりよろしくないと思うのでReleaseの方法が分かり次第変更する予定です。

コメント

タイトルとURLをコピーしました