I have included code which produces hexadecimal output that I think may help you understand floating-point numbers. Here is an example:
double: 00 00 A4 0F 0D 4B 72 42 (1257096936000.000000) (+0x1.24B0D0FA40000 x 2^40)
From my code example below, it should become obvious to you how to output the bits. Cast the double's address to unsigned char *
and output the bits of sizeof(double)
chars.
Since I want to output the exponent and significand (and sign bit) of a floating-point number, my example code digs into the bits of the IEEE-754 standard representation for 64-bit 'double precision' floating pointing point in radix 2. Therefore I do not use sizeof(double)
other than to verify that the compiler and I agree that double
means a 64-bit float.
If you would like to output the bits for a floating-point number of any type, do use sizeof(double)
rather than 8
.
void hexdump_ieee754_double_x86(double dbl)
{
LONGLONG ll = 0;
char * pch = (char *)≪
int i;
int exponent = 0;
assert(8 == sizeof(dbl));
// Extract the 11-bit exponent, and apply the 'bias' of 0x3FF.
exponent = (((((char *)&(dbl))[7] & 0x7F) << 4) + ((((char *)&(dbl))[6] & 0xF0) >> 4) & 0x7FF) - 0x3FF;
// Copy the 52-bit significand to an integer we will later display
for (i = 0; i < 6; i ++)
*pch++ = ((char *)&(dbl))[i];
*pch++ = ((char *)&(dbl))[6] & 0xF;
printf("double: %02X %02X %02X %02X %02X %02X %02X %02X (%f)",
((unsigned char *)&(dbl))[0],
((unsigned char *)&(dbl))[1],
((unsigned char *)&(dbl))[2],
((unsigned char *)&(dbl))[3],
((unsigned char *)&(dbl))[4],
((unsigned char *)&(dbl))[5],
((unsigned char *)&(dbl))[6],
((unsigned char *)&(dbl))[7],
dbl);
printf( "\t(%c0x1.%05X%08X x 2^%d)\n",
(((char *)&(dbl))[6] & 0x80) ? '-' : '+',
(DWORD)((ll & 0xFFFFFFFF00000000LL) >> 32),
(DWORD)(ll & 0xFFFFFFFFLL),
exponent);
}
Nota Bene: The significand is displayed as a hexadecimal fraction ("0x1.24B0D0FA40000") and the exponent is display as decimal ("40"). For me, this was an intuitive way to display the floating-point bits.