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

Claudio
  • 10,614
  • 4
  • 31
  • 71
Num Lock
  • 3
  • 4
  • 3
    `int64_t *pointer = (int64_t *) &d;` is undefined behavior because of strict aliasing rule. – kiran Biradar May 16 '19 at 12:59
  • what do you mean by strict aliasing rule? – Num Lock May 16 '19 at 13:00
  • 2
    read yourself [what-is-the-strict-aliasing-rule](https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule) – kiran Biradar May 16 '19 at 13:01
  • 1
    In C it's explicitly allowed to use a `union` for [*type punning*](https://en.wikipedia.org/wiki/Type_punning) (to side-step the strict aliasing rule). – Some programmer dude May 16 '19 at 13:02
  • 2
    Avoid using signed integers with bit shifting operations. Since the sign bit has a special meaning, it does not act like “just a bit.” Unsigned integers are closer to “just plain bits” and hence are generally more suitable for bitwise operations. Right-shifting a negative value is implementation-defined. Your implementation, like many, replicates the sign bit as it shifts. In a signed integer, this causes 10000…0000 to become 11111…1111, which represents −1. – Eric Postpischil May 16 '19 at 13:26
  • shifting a signed integer 64bit by 63 places to the right is U.B. why don't you just check the bit by masking it with `if (*pointer & 0x8000000000000000)` ??? – Luis Colorado May 17 '19 at 20:54
  • You can just check `if (*pointer < 0)` because the sign bit in a `int64_t` integer is in the same place as the sign bit in a `double`. – Luis Colorado May 17 '19 at 20:57

3 Answers3

3

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.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
0

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); 
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
0

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");
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Hi! I don't understand this syntax : if ((union { double dd; int64_t i64; }){ .dd = d }.i64 < 0), can u please; ty! – Num Lock May 18 '19 at 15:24