浮動小数点数は IEEE-754 という規格で標準化されている。たとえば32ビットで表現するとき、上位1ビットが符号に、次の8ビットが指数部に、残りの下位23ビットは仮数部として割り当てられ、これら3つのフィールドが合同してひとつの浮動小数点数を表現する。
あるいはこの図をみると「ああ、あれね」と思い出すこともあろうかとおもう。
32ビットの整数値を浮動小数点のフォーマットに変換するエクササイズをやっていて、困ったことがあった。それは IEEE-754 に準拠したビット表現を手軽に print する手段が提供されていないことである。たとえばこれは動かない例である。気軽に %x
で16進数を書き出そうとしている。
float f = 1.0;
printf("%x\n", f);
// warning: format specifies type 'unsigned int' but the argument has type 'float' [-Wformat]
実に、 printf
の %x
オプションは unsigned int
を要求していて1、何も考えずに float
を突っ込んで魔法のようにうまくいくことはない。
かといって、 IEEE-754 に準拠した print を自力で実装することはできない。そもそも標準規格への理解が足らないがゆえに print を欲しているわけで、何かしらうまく動くプログラムを他力本願に望むほかなにもできない。
で、 StackOverflow にてそれに近いものを発見した。リンクはこれである。あらかじめ告白すると、いったいなにをやっているコードなのかはわからない。わからないながらに、少なくとも便利に使えるとは判断できるため、いまの未熟な理解度を記録する目的も込めて書く。
それがこんな関数である。
void print_i3_754(float r)
{
union {
float f;
unsigned int u;
} f2u = { .f = r };
printf("0x%.8x\n", n);
}
使ってみよう。
int main()
{
int x = 3'510'593;
float y = x;
printf("0x%.8x\n", x);
print_i3_754(y);
return 0;
}
// x = 0x00359141
// y = 0x4a564504
と、期待通りの表現が得られた。