0

I am currently learning the process of bitwise operators, and I've come across something that I can't quite figure out.

Im currently working with the NOT(~) operator, which should invert all of the bits. So in order to get a better understanding of it, I've tried creating a program that will flip the number 1's bits.

int main()
{
    int x = 1; // 0001 in binary
    int y = ~x; // should flip the bits, so its 1110, or 14
    cout << y; 
}

However, when running this, i am getting -2 as the result. Can anyone offer an explanation as to why this isn't working?

alinsoar
  • 15,386
  • 4
  • 57
  • 74
  • 4
    Where you have written, in a comment, `0001 in binary`, how did you decide that there should be exactly three leading `0`s? Also: how do you imagine that negative numbers are represented in binary? Have you heard of *two's complement*? – Karl Knechtel Feb 14 '22 at 20:01
  • This question's title should make it an excellent landing point for future Askers. – user4581301 Feb 14 '22 at 20:20
  • `int y = ~x & 0b1111;` – Eljay Feb 14 '22 at 21:12

1 Answers1

6

You're using signed integers. Your expected result (14) would occur if you were using unsigned integers (and if the integer were only 4 bits, which it is not).

Instead, with signed integers, all values with the highest bit set are negative values - that's how Two's Complement works. For example, if you have 16 bits, then values 0b0000_0000_0000_0000 through 0b0111_1111_1111_1111 are assigned to the positive values ("0" through "32767") meanwhile values 0b1000_0000_0000_0000 through 0b1111_1111_1111_1111 are assigned to the negative values ("-32768" through "-1").

Also, int usually is more than 4 bits; it's often 32-bits. The negation of 1 would be 0b1111_1111_1111_1111_1111_1111_1111_1110, not 0b1110.

0b1111_1111_1111_1111_1111_1111_1111_1110 when treated as a signed integer is -2 using the Two's Complement rules.

0b1111_1111_1111_1111_1111_1111_1111_1110 when treated as an unsigned integer is 4,294,967,294, equal to 2^32 - 2.

#include <stdio.h>
#include <cstdint>

// Program prints the following:
//   unsigned int_8:   254
//   signed   int_8:   -2
//   unsigned int_16   65534
//   signed   int_16   -2
//   unsigned int_32   4294967294
//   signed   int_32   -2

int main() {
    printf( "unsigned int_8:   %hhu\n", (uint8_t)~1 );
    printf( "signed   int_8:   %d\n", (int8_t)~1 );

    printf( "unsigned int_16   %hu\n", (uint16_t)~1 );
    printf( "signed   int_16   %d\n", (int16_t)~1 );

    printf( "unsigned int_32   %u\n", (uint32_t)~1 );
    printf( "signed   int_32   %d\n", (int32_t)~1 );
}
antiduh
  • 11,853
  • 4
  • 43
  • 66
  • Hi, I've tried uint16_t (unsigned 16 bit) for x uint16_t x = 1; x = ~x which results in the max value it can hold -1 (65534), along with the 32 bit variation. additionally, ive just gone with unsigned int x = 1 which gives a similar output(respecting their ranges) – James Radcliff Feb 14 '22 at 19:55
  • 2
    "Hi, I've tried uint16_t (unsigned 16 bit) for x uint16_t x = 1; x = ~x which results in the max value it can hold -1 (65534)" Okay; and *are you confused* by this result? If so, *why*? What did you expect *instead*? Why? – Karl Knechtel Feb 14 '22 at 20:02