4

I wonder why the code below prints "wrong".

double x = 0x8000000000000000;
signed long long v1 = (signed long long)(x);
signed long long v2 = *(signed long long *)(&x);
printf( v1 == v2? "correct\n" : "wrong\n" );

I tried to print out binary representation of v1 and v2 respectively by code below:

printf( "v1 = 0b" );
for ( int i = 63; i > 0; i-- ) {
    printf( "%d", ( ( v1 >> i ) & 1 ) );
}
printf( "\n" );

printf( "v2 = 0b" );
for ( int i = 63; i > 0; i-- ) {
    printf( "%d", ( ( v2 >> i ) & 1 ) );
}
printf( "\n" );

It turns out v1 is correct, but v2 is 0b010000111110000000000000000000000000000000000000000000000000000.

Could anyone be so kind to teach what happens here?

Also, I was wondering if C standard offers any way of printing out underlying representation of binary or hex, such that my print scheme can be replaced by an one-line function call?

8
  • What do you think the value of x is? Commented Dec 1 at 9:00
  • 1
    (signed long long) you shouldn't do this at all in C++. And this double x = 0x8000000000000000; is also not going to do what you think it does. (It will not initialize using a bit-pattern but maps an integer number on the "closest" representable floating point number Commented Dec 1 at 9:07
  • Many thanks to you guys for commenting. Mind elaborating? If x is not what I expect, what essentially is it in memory?
    – PkDrew
    Commented Dec 1 at 9:10
  • @PkDrew IEEE 754 is a common representation of floating point numbers. The first bit is the sign bit, then the exponent and then the fraction. It's very different than the representation of integral types.
    – wohlstad
    Commented Dec 1 at 9:14
  • 1
    Because that is a "C" style cast, in C++ you have "reinterpret_cast" or probably better (for type punning) std::bit_cast\ Commented Dec 1 at 13:36

1 Answer 1

3

In the first case

signed long long v1 = (signed long long)(x);

the compiler performs conversion from double to signed long long.

In the second case

signed long long v2 = *(signed long long *)(&x);

the compiler interprets the internal representation of stored double as an object of the type signed long long.

Pay attention to that float numbers are internally stored in special formats.

From the C23 Standard Draft n3088:

2 The following parameters are used to define the model for each floating type:

s sign (±1)

b base or radix of exponent representation (an integer > 1)

e exponent (an integer between a minimum emin and a maximum emax)

p precision (the number of base-b digits in the significand)

fk nonnegative integers less than b (the significand digits)

For each floating type, the parameters b, p, emin, and emax are fixed constants.

As for your last question then if I am not mistaken then in the C23 Standard there is introduced conversion specifier b that allows to output integer numbers in a binary representation.

As for C++ then starting from the C++20 Standard you can use format specifier b or B inside format output (see the description of the header <format>)

6
  • Many thanks for answering mate, kindly pardon my dullness and give some more details regarding the second case?
    – PkDrew
    Commented Dec 1 at 9:11
  • @PkDrew Floating numbers are stored as separate parts that represent a mantissa, exponent , and sign. Commented Dec 1 at 9:24
  • Thanks Vlad, guess I sort of understood. So by double x = 0x8000000000000000, I effectively got a 64-bit pattern, which, however, is not 0b10000(0 repeated 63 times) that I expected, instead, it is a whichever pattern that compiler used to represent the number (double)0x8000000000000000, am I right? BTW, I quickly tested the %b format and found it works.
    – PkDrew
    Commented Dec 1 at 10:18
  • @PkDrew Yes, you are right.:) Commented Dec 1 at 10:21
  • 1
    This site 10base IEEE754 will allow you to see the IEEE754 machine level representation of a double or single precision floating point number. The binary bit pattern that you started out with would if interpreted directly as an IEEE754 double be literally '-0'. Conversion to double represented it as the integer value +1.0 x 2^63 (implicit leading 1 not stored). Commented Dec 1 at 10:25

Not the answer you're looking for? Browse other questions tagged or ask your own question.