Num Lock
Num Lock

Reputation: 3

right shifting the binary representation of the floating point number -0.0

I am doing a program to check the sign of a double/float number, first of all I cast the pointer of the number into a long int, then I check the sign bit if it's 0 or 1. I don't understand why the printing of the sign bit with this operation *pointer >> 63 is -1 instead of 1?(assuming *pointer is the int64_t that I casted my double/float into)

This is the entire code :

    double d = -0.0;
    int64_t *pointer = (int64_t *) &d;
    if (*pointer >> 63)
       printf("negative number\n");
    else
       printf("positive number\n");
    // if i print the result of (*pointer >> 63), it gives me -1
    // so how can this go inside my if condition?

By the way the binary printing of -0.0 in 64 bits gives me 100000000...000

Upvotes: 0

Views: 84

Answers (3)

chux
chux

Reputation: 153348

so how can this go inside my if condition?

1 Use signbit(d)

if (signbit(d)) {
  puts("Negative");
}

or

2 Use a compound literal and union.

//  v--------------------------------------------v  compound literal
if ((union { double dd; int64_t i64; }){ .dd = d }.i64 < 0) {
  puts("Negative");
}

This approach needs to have the expected size, and a double encoding with the sign bit in the same place as int64_t.

// Test size
_Static_assert(sizeof(int64_t) == sizeof(double), "Mis-match size");

Upvotes: 0

Serge Ballesta
Serge Ballesta

Reputation: 148880

First, right shifting a negative integer is implementation defined. Next dereferencing a pointer of a type different from the actual type is explicitely undefined behaviour because of the strict aliasing rule (google for it it you do not know it).

If you want your code to be portable, the only foolproof way is to use memcpy to transport the representation of the value. This only assumes that:

  • sizeof(double) is the same as sizeof(uint64_t):
  • the sign bit is bit63 of an uint64_t having that representation

Code:

double d = -0.0;
uint64_t u;

memcpy(&u, &d, sizeof(u));

print("Sign bit in that architecture %d\n", u>>63); 

Upvotes: 1

Bathsheba
Bathsheba

Reputation: 234655

This is hard to do in full generality due to the existence of signed zeros in floating point types, and the possibility of 1's complement integral types.

Aside from the undefinedness of (int64_t*)&d (which you could address with a union type-pun), that approach will return the wrong sign for -0.0.

Fortunately you can use signbit() from math.h that probably implements the function in a non-portable manner.

Upvotes: 3

Related Questions