2

I want to initialise a double with a hex constant.

double dbl = 0xFEDCBA9876543212;
printf("dbl: %llX\n", (uint64_t)dbl);

I would expect to see as the output:

dbl: FEDCBA9876543212

But I am getting:

dbl: FEDCBA9876543000

Why is this and why are the last 3 bytes being dropped off?

John
  • 10,837
  • 17
  • 78
  • 141
  • Doing so could cost billions of dollars! Seen that, been there ... – πάντα ῥεῖ Sep 18 '14 at 22:14
  • 2
    Being itself a 64-bit datatype, `double` can't represent the full precision of a 64-bit integer value, since it also needs space for the exponent part. – 500 - Internal Server Error Sep 18 '14 at 22:16
  • Punch "what every computer scientist should know about floating point" into your favorite search engine. – David Schwartz Sep 18 '14 at 22:20
  • 1
    @DavidSchwartz I would be nice, if you would give the actual link here: ["what every computer scientist should know about floating point"](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – πάντα ῥεῖ Sep 18 '14 at 22:22
  • You are assiging an integer value to a `double` - my guess is that you actually want to assign the bitwise equivalent value as a `double`, in which case you will need to use `reinterpret_cast` as Zak suggests. – Mats Petersson Sep 18 '14 at 22:32
  • I am actually writing some code which involves splitting up a double (64 bits) into 2 x uint32_t variables for transmission over a particular network type. For my unit tests, I want to set all 64 bits of the double to a known value, check each uint32_t, recombine the 2 x uint32_t and check the resulting double against the double at the start. – John Sep 18 '14 at 22:40
  • You can, as I wrote below, specify the exact bit patterns of a floating point in C with hex float literals. But otherwise, I'd be more concerned about the value actually being correct the other end - it's fairly obvious for nearly all float values (assuming IEEE-754) when you start mixing bytes or words up - except for zero, getting just a few bits wrong typically gives a completely different number [I'd also check that the bytes received the other end before conversion back to double is correct - e.g. if you expect 0x12, 0x34, 0x56, 0x78, ... then you can check that first. – Mats Petersson Sep 18 '14 at 22:50

5 Answers5

4

You are using a 64-bit value to initialize a double, which only holds 53 significant bits. There's one bit of rounding, and the remaining bits are just lost.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
2

If you are just wanting to do a memcpy style transaction you can try:

uint64_t x = 0xFEDCBA9876543212;
double dbl = *reinterpret_cast<double *>(&x);

Also, your test may not be doing what you want:

My test:

#include <cstdint>
#include <cstdio>

int main (void) {
  // Move the underlying hex value through multiple types
  uint64_t x = 0xFEDCBA9876543212;
  double dbl = *reinterpret_cast<double *>(&x);
  uint64_t y = *reinterpret_cast<uint64_t *>(&dbl);

  // Check integrity of the result
  printf("dbl: %llX\n", (uint64_t)dbl);  //your test
  printf("x: %llx\ny: %llx\n", x, y);  //my test

  return 0;
}

Output:

dbl: 8000000000000000
x: fedcba9876543212
y: fedcba9876543212

As you can see, the underlying binary value remains the same as it passes from x to dbl to y, even though your current test printf("dbl: %llX\n", (uint64_t)dbl); produces unexpected output.

Zak
  • 12,213
  • 21
  • 59
  • 105
2

If you want to know exactly the value of your double, then use the hex format of doubles,

0x1.01234567898abcp-12

and then print the number with printf("%p", number); once you have assembled the number at the other end. The number should match the input if you have the right number of digits.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
1

double precision is 53 bits, that's why you are getting zeros on remaining positions.

Anton Savin
  • 40,838
  • 8
  • 54
  • 90
0

In addition to the accepted answer, you can also use unions

union
{
    long long _double_exact;
    double _double;
};
double_exact = 0xFEDCBA9876543212;
Beyondo
  • 2,952
  • 1
  • 17
  • 42