1

As shown in the code below, I am trying to copy the bits from a long longnum to two doubles, d1 and d2, using different methods: pointer-casting + dereferencing and 'bitwise-and'ing respectively.

# include <stdio.h>

int main(void) {
    long longnum = 0xDDDDDDDDDDDDDDDD;
    double d1 = *((double*)(&longnum));
    double d2 = longnum & 0xFFFFFFFFFFFFFFFF;

    printf("%ld\n\n",longnum);
    printf("%lf\n\n",d1);
    printf("%lf\n",d2);
    return 0;
}

The issue is that both the doubles are not printed the same way, as shown in the output below.

-2459565876494606883

-1456815990147462891125136942359339382185244158826619267593931664968442323048246672764155341958241671875972237215762610409185128240974392406835200.000000

15987178197214945280.000000

Given the size of DBL_MAX, the max size of a double, it seems to me that it's the giant number that's actually the sensible output of the two doubles printed.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
Captain_Obvious
  • 520
  • 5
  • 15

2 Answers2

3
double d2 = longnum & 0xFFFFFFFFFFFFFFFF;

The & mask doesn't do anything. A number ANDed with all 1's is the same number. The line above is no different from:

double d2 = longnum;

That line doesn't do any bit reinterpretation. Instead it sets d2 to the double that most closely represents the value in longnum. The value will be similar; the bit pattern will be quite different.

The best way to do what you're trying to do is with a union. Unions are the best way to perform type punning.

union {
     long l;
     double d;
} u;

u.l = longnum;
printf("%f\n\n", u.d);

Using pointers as you did with d1 technically invokes undefined behavior. It is a common idiom and in practice will probably work fine, but type punning with pointers ought to be avoided.

Community
  • 1
  • 1
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • "Unions are the most direct way" - actually they are the only compliant way, if not one type is `char`. – too honest for this site Oct 24 '16 at 17:57
  • 1
    But this type puning is illegal. Don't suggest using it. – Eugene Sh. Oct 24 '16 at 17:57
  • @EugeneSh.: Huh? The standard explicitly allows it as one application for `union`s. Of course it is all implementation defined. – too honest for this site Oct 24 '16 at 17:57
  • 1
    but it is not defining the result of `u.l=5; printf("%lf", u.d);` I think even not implementation specific – Eugene Sh. Oct 24 '16 at 17:58
  • The union method is valid as long as `long` and `double` are the same size. – John Kugelman Oct 24 '16 at 18:00
  • @2501 There is an intersting article [here](https://davmac.wordpress.com/2010/02/26/c99-revisited/). Also discussing some apparent exception about the trap representation in the union fields.. – Eugene Sh. Oct 24 '16 at 18:08
  • [N1570](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf), 6.5.2.3, footnote 95: " If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type punning’’). **This might be a trap representation**." Emphasis added. – John Bode Oct 24 '16 at 18:10
  • "The line above is no different" but I am curious as to why the wrong value `15987178197214945280.000000` is printed when using the mask, but not when no mask is applied. – Weather Vane Oct 24 '16 at 18:14
  • But using the mask `0x7FFFFFFFFFFFFFFF` gives the correct result. – Weather Vane Oct 24 '16 at 18:22
0

your problem is

d1 = *((double*)(&longnum));

by doing the above you are incorrectly taking the contents from memory and then assuming it is in double precision format.

if you do it by the following:

d1 = (double) longnum;

then the contents of the memory space longnum, which is an 8 byte integer, is converted properly and then stored properly in memory at the location pointed to by d1. And then the contents of d1 will be correct. suggest you read the wikipedia page about "Double-precision floating-point format"

the value of a floating point value (or double precision value) is stored differently in memory than how integers are. https://en.wikipedia.org/wiki/Double-precision_floating-point_format

ron
  • 967
  • 6
  • 23