これは、Mac OS X 10.7.5 上の GCC 4.7.1 でコンパイルおよび実行できるコードの拡張です。
#include <stdio.h>
#include <inttypes.h>
static void example(float f)
{
unsigned int u = *(unsigned int*)&f;
printf("%13.6e: %10u = 0x%08X (address 0x%08" PRIXPTR ")\n",
f, u, u, (uintptr_t)&f);
}
int main(void)
{
example(+3.14159F);
example(+0.0);
example(-0.0);
example(+3.456789e24);
example( 3.456789e-24);
example(-3.456789e24);
example(-3.456789e-24);
return(0);
}
出力:
3.141590e+00: 1078530000 = 0x40490FD0 (address 0x7FFF5FD3754C)
0.000000e+00: 0 = 0x00000000 (address 0x7FFF5FD3754C)
-0.000000e+00: 2147483648 = 0x80000000 (address 0x7FFF5FD3754C)
3.456789e+24: 1748435002 = 0x6837003A (address 0x7FFF5FD3754C)
3.456789e-24: 411417185 = 0x1885BA61 (address 0x7FFF5FD3754C)
-3.456789e+24: 3895918650 = 0xE837003A (address 0x7FFF5FD3754C)
-3.456789e-24: 2558900833 = 0x9885BA61 (address 0x7FFF5FD3754C)
ご覧のとおり、私は 64 ビット マシンを使用しています。符号ビットが最上位バイトにあることを 16 進数で確認できます。あまり明白ではありませんが、指数は次の 8 ビットにあり、仮数は残りの 23 ビットにあることです。
タイプミスが修正されると、あなたのコードは私が示しているものに非常に近いものになります。MASK
何が何であるかを示していないため、使用しているコードは神秘的MASK
です。ただし、正のゼロ (その後u&u
false と評価されるため) を除くほとんどすべての float 値、または に一致するビット パターンを持つ 1 つの特定の float 値の情報を出力する必要がありますMASK
。
私のコードでは、コンパイラは次のように警告します。
$ gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition x.c -o x
x.c: In function ‘example’:
x.c:6:5: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
$
別の拡張機能と、より多くのサンプル出力を次に示します。
#include <stdio.h>
#include <inttypes.h>
static void example(float f)
{
unsigned int u = *(unsigned int*)&f;
unsigned int s = u >> 31;
unsigned int e = (u >> 23) & 0xFF;
unsigned int m = (u >> 16) & 0x7F;
printf("%13.6e: %10u = 0x%08X (s=%u, e=x%02X, m=0x%02X) (0x%08" PRIXPTR ")\n",
f, u, u, s, e, m, (uintptr_t)&f);
}
int main(void)
{
example(+3.14159F);
example(+0.0);
example(-0.0);
example(+1.0);
example(-1.0);
example(+2.0);
example(-2.0);
example(+3.0);
example(-3.0);
example(+4.0);
example(-4.0);
example(+5.0);
example(-5.0);
example(+3.456789e24);
example( 3.456789e-24);
example(-3.456789e24);
example(-3.456789e-24);
return(0);
}
出力:
3.141590e+00: 1078530000 = 0x40490FD0 (s=0, e=x80, m=0x49) (0x7FFF6112754C)
0.000000e+00: 0 = 0x00000000 (s=0, e=x00, m=0x00) (0x7FFF6112754C)
-0.000000e+00: 2147483648 = 0x80000000 (s=1, e=x00, m=0x00) (0x7FFF6112754C)
1.000000e+00: 1065353216 = 0x3F800000 (s=0, e=x7F, m=0x00) (0x7FFF6112754C)
-1.000000e+00: 3212836864 = 0xBF800000 (s=1, e=x7F, m=0x00) (0x7FFF6112754C)
2.000000e+00: 1073741824 = 0x40000000 (s=0, e=x80, m=0x00) (0x7FFF6112754C)
-2.000000e+00: 3221225472 = 0xC0000000 (s=1, e=x80, m=0x00) (0x7FFF6112754C)
3.000000e+00: 1077936128 = 0x40400000 (s=0, e=x80, m=0x40) (0x7FFF6112754C)
-3.000000e+00: 3225419776 = 0xC0400000 (s=1, e=x80, m=0x40) (0x7FFF6112754C)
4.000000e+00: 1082130432 = 0x40800000 (s=0, e=x81, m=0x00) (0x7FFF6112754C)
-4.000000e+00: 3229614080 = 0xC0800000 (s=1, e=x81, m=0x00) (0x7FFF6112754C)
5.000000e+00: 1084227584 = 0x40A00000 (s=0, e=x81, m=0x20) (0x7FFF6112754C)
-5.000000e+00: 3231711232 = 0xC0A00000 (s=1, e=x81, m=0x20) (0x7FFF6112754C)
3.456789e+24: 1748435002 = 0x6837003A (s=0, e=xD0, m=0x37) (0x7FFF6112754C)
3.456789e-24: 411417185 = 0x1885BA61 (s=0, e=x31, m=0x05) (0x7FFF6112754C)
-3.456789e+24: 3895918650 = 0xE837003A (s=1, e=xD0, m=0x37) (0x7FFF6112754C)
-3.456789e-24: 2558900833 = 0x9885BA61 (s=1, e=x31, m=0x05) (0x7FFF6112754C)
これは、IEEE 754 単精度浮動小数点形式を詳細に分析し始めています。s
参照されているウィキペディアのページには、e
、 、の作成に使用した値が関連する理由に関する詳細が記載されていますm
(Intel マシンで作業しているため、これはリトル エンディアン データであることに注意してください)。
「段階的アンダーフロー」値、ゼロ、無限大、および NaN を除いて、「実際の」仮数部の最初のビットは常に 1 であるため、形式は実際にはそれを格納しません。これは、1、2、4 の値からわかります。3 と 5 とは対照的です (3 と 5 のバイナリ表現には 2 つのセット ビットが含まれていますが、それぞれの仮数には 1 ビットしかセットされていません)。