Why does NOT give an unexpected result when flipping 1?

136 views Asked by At

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?

1

There are 1 answers

2
antiduh On

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 );
}