6

I have an unsigned long long (or uint64_t) value and want to convert it to a double. The double shall have the same bit pattern as the long value. This way I can set the bits of the double "by hand".

unsigned long long bits = 1ULL;
double result = /* some magic here */ bits;

I am looking for a way to do this.

pvorb
  • 7,157
  • 7
  • 47
  • 74
  • 2
    Are you asking how to do this? Having a hard time parsing a *question* out of this. – WhozCraig Jul 01 '13 at 16:21
  • 3
    In C99, you can legally do this via a union. In C++, you'd have to do it using a `memcpy()`. – Mysticial Jul 01 '13 at 16:23
  • If'n yer feelin' like bein' a dangerous badboy, yer tool o' choice would be somethin' like a [this here cast, young feller.](https://dl.dropboxusercontent.com/u/17644642/cowboy_cast.png) –  Jul 01 '13 at 16:36

4 Answers4

16

The portable way to do this is with memcpy (you may also be able to conditionally do it with reinterpret_cast or a union, but those aren't certain to be portable because they violate the letter of the strict-alias rules):

// First, static assert that the sizes are the same
memcpy(&result, &bits, sizeof(bits));

But before you do make sure you know exactly what you're doing and what floating point representation is being used (although IEEE754 is a popular/common choice). You'll want to avoid all kinds of problem values like infinity, NaN, and denormal numbers.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • 2
    I believe the standard actually allows you to "reinterpret_cast(bits)" in this case, as both types are standard-layout, assuming double doesn't require a more strict alignment. – DanielKO Jul 01 '13 at 21:48
6

Beware of union and reinterpret_cast<double*>(&bits), for both of these methods are UB. Pretty much all you can do is memcpy.

Puppy
  • 144,682
  • 38
  • 256
  • 465
0

since C++ 20 we have std::bit_cast() to to such conversions

example:

double d = 1.5;
uint64_t i = std::bit_cast<uint64_t>(d); //use the same bits in an integer
double dd = std::bit_cast<double>(i); //back to floating point again
ray_ray_ray
  • 316
  • 1
  • 14
-3

The following uses a void pointer.

unsigned long long bits = 1ULL;
void* tempPtr=(void*)&bits;
double result = *(double*)tempPtr;
IanPudney
  • 5,941
  • 1
  • 24
  • 39
  • 5
    Undefined behaviour- strict aliasing violation. This is the same as dasblinkenlight's answer but with a completely pointless temporary. – Puppy Jul 01 '13 at 16:29
  • I was aware that my answer is the same as dasblinkenlight's, but since it uses a completely different syntax it appears to be a different method. Thus, I felt it was appropriate to post as an answer to the question. And as for the fact that it is undefined behavior, I do not know of one compiler or system that is incapable of handlng this (provided both variables are the same size). – IanPudney Jul 01 '13 at 16:35
  • 2
    The addition of the temporary is utterly meaningless, the method is identical. Also, it's undefined behaviour, and that's that. – Puppy Jul 01 '13 at 16:36