-3

Hello I have a question regarding doubles. I am on IA32 machine and want to see how double is represented in memory. Below I have a program.

int main(int argc, char *argv[])
{  
  double d = 0.333333333333333314829616256247390992939472198486328125; //in hex: 3FD5 5555 5555 5555
  printf("%x\n", d); //prints 55555555
  return 0;
}

For some reason this only prints the latter 4 bytes which is 5555555. My question is where are the high bits (3FD5 5555) stored? is it at address (&d + 4)? or (&d - 4) or somewhere else defined in memory? Since double has 8 bytes how is it stored on a 32 bit machine?

Mark
  • 8,408
  • 15
  • 57
  • 81
  • Following the low-order bytes. It's just that %x assumes a dword. – 500 - Internal Server Error Mar 09 '14 at 01:05
  • Hmm why the negative downvotes? – Mark Mar 09 '14 at 01:11
  • Are people down voting because they think it's off topic or because they can't grab fast karma points off of it? – Mark Mar 09 '14 at 01:21
  • 1
    @Mark: probably because it's not a very useful question. The high part of a double is stored next to the low part, just like the high 16 bits of an int are stored next to the low 16 bits, and the high 8 bits of a short are stored next to the low 8 bits. The reason it only prints 4 bytes is that %x prints an int, which is 4 bytes (on your system). – user253751 Mar 09 '14 at 02:09

3 Answers3

2

I'm not going to say the following is "correct" by any means, but it Works Here (TM) - or really on whatever compiler/machine ideone uses (for the continuation of this answer I will assume it is a modern x86 target) - and can be used for examining the individual bytes/bits of the double value.

#include <stdio.h>

int main(void) {
    double d = (double)1/3;

    unsigned char *x = (unsigned char *)&d;     
    printf("chars: %2x%2x %2x%2x %2x%2x %2x%2x\n",
        x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7]);

    // as per Yu Hao's answer       
    long long dd = *(long long*)&d;
    printf("lld  : %8llx\n", dd);

    return 0;
}

Result:

chars: 5555 5555 5555 d53f   // raw view doesn't account for LE/reversal
lld  : 3fd5555555555555      // this is the "correct" value

The values in the two outputs are different due to the little-endian nature (within each pair of bytes) of how the integer is encoded in memory (and that the MSB affects the magnitude the most), while the individual chars are "in sequence of memory".

With 1234.5678 as input the results are:

chars: adfa 5c6d 454a 9340
lld  : 40934a456d5cfaad

And with some unscrambling, a correlation can be seen:

chars: AAaa BBbb CCcc DDdd
lld  : ddDDccCCbbBBaaAA
user2864740
  • 60,010
  • 15
  • 145
  • 220
1

In most machines today, double has 8 bytes, try using long long(at least 64 bits) like this:

printf("%llx\n", *(long long*)(&d)); 
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • 1
    Since double has 8 bytes how is it stored in memory on a 32 bit machine? – Mark Mar 09 '14 at 01:07
  • @Mark Using two machine words? You may ask the same question about `long long`, etc. – Yu Hao Mar 09 '14 at 01:09
  • Yes, but how are the two machine words structured in memory? – Mark Mar 09 '14 at 01:10
  • @Mark A "32-bit x86 CPU" means that the *word size* is 32-bits; x86 CPUs have been able to handle floats directly for awhile .. https://www.cs.uaf.edu/2011/fall/cs301/lecture/11_11_FPU_SSE_AVX.html – user2864740 Mar 09 '14 at 01:13
  • @Mark Is [Endianess](http://en.wikipedia.org/wiki/Endianness) what you are looking for? – Yu Hao Mar 09 '14 at 01:14
  • I know each memory address holds 4 bytes and a double is represented using two memory addresses. But which two memory addresses are chosen to represented the double? Since the high bits are neither located in (&d+4) or (&d-4). – Mark Mar 09 '14 at 01:16
  • @Mark Uh, why does "each memory address 'hold' 4 bytes"? That's just wrong, which I believe leads the to following error reveled above: `(&d+4) or (&d-4)` is offsetting the address by +/- `sizeof(d)*4` bytes. – user2864740 Mar 09 '14 at 01:21
  • @user2864740: so when I declare a double, two consecutive memory registers are assigned ? – Mark Mar 09 '14 at 01:24
  • @Mark That's an orthogonal topic to the error indicated (and is entirely left up to the implementation and target). You can tell your compiler [to emit the intermediate/effective assembly](http://stackoverflow.com/questions/1289881/using-gcc-to-produce-readable-assembly) for visual inspection. (Doing so will also reveal that the presumed +/- 4 offsets are really +/- 16/32 byte offsets, whoops!) – user2864740 Mar 09 '14 at 01:25
  • 1
    @Mark (And do be aware that the very act of using pointers-to-integrals to try and access the "raw bits" within the function might influence how the compiler chooses to the compile the given code.) – user2864740 Mar 09 '14 at 01:30
  • @user2864740: arggg I see. I believed (&d+4) was address of d + 4. How would one chop a double into chars or individual bytes? – Mark Mar 09 '14 at 01:31
  • @Mark Although I'm pretty sure it's "not well defined" by the C standard, `unsigned char *x = (unsigned char*)&double;` should allow access to a bit-representation of the double value via `x[0..7]` on a typical x86 target/build. Also, perhaps overlaying with a struct .. – user2864740 Mar 09 '14 at 01:33
  • @user2864740: It doesn't seem to return the correct result. – Mark Mar 09 '14 at 01:36
1

A portable method to see the hexadecimal nature of a double. "%a" prints double in hexadecimal significand and decimal exponent notation.

printf("%a\n", d);

A not completely, but reasonable portable method.
This works even if long long is more than 8 bytes.
(A long long that is not the same size as double is uncommon these days.)

#include <inttypes.h>
...
printf("%016" PRIX64 "\n", *(uint64_t *) &d);`
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256