Printing double
value r
using format %#lX
actually has undefined behavior.
You have been lucky to get the 64-bits that represent the value 12.0
as a double
, unless r
has type unsigned long
and was initialized from the value 12.0
this way:
unsigned long r;
double d = 12.0;
memcpy(&r, &d, sizeof r);
printf("%#lX", r);
But type unsigned long
does not have 64-bits on all platforms, indeed it does not on the 32-bit intel ABI. You should use the type uint64_t
from <stdint.h>
and the conversion format from <inttypes.h>
:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
int main() {
int x = 12;
printf("int: %#X [", x);
for (size_t i = 0; i < sizeof x; i++) {
printf(" %02X", ((unsigned char *)&x)[i]);
}
printf(" ]\n");
double d = 12.0;
uint64_t r;
memcpy(&r, &d, sizeof r);
printf("double: %#"PRIX64" [", r);
for (size_t i = 0; i < sizeof d; i++) {
printf(" %02X", ((unsigned char *)&d)[i]);
}
printf(" ]\n");
printf("sign bit: %d\n", (int)(r >> 63));
printf("exponent: %d\n", (int)((r >> 52) & 2047));
unsigned long long mantissa = r & ((1ULL << 52) - 1);
printf("mantissa: %#llX, %.17f\n",
mantissa, 1 + (double)mantissa / (1ULL << 52));
return 0;
}
Output:
int: 0XC [ 0C 00 00 00 ]
double: 0X4028000000000000 [ 00 00 00 00 00 00 28 40 ]
sign bit: 0
exponent: 1026
mantissa: 0X8000000000000, 1.50000000000000000
As explained in the article Double-precision floating-point format, this representation corresponds to a positive number with value 1.5*21026-1023, ie: 1.5*8 = 12.0.