Mahesha999
Mahesha999

Reputation: 24871

Understanding bitwise NOT in python

I was trying to understand bitwise NOT in python.

I tried following:

print('{:b}'.format(~ 0b0101)) 
print(~ 0b0101)

The output is

-110
-6

I tried to understand the output as follows:

Bitwise negating 0101 gives 1010. With 1 in most significant bit, python interprets it as a negative number in 2's complement form and to get back corresponding decimal it further takes 2's complement of 1010 as follows:

 1010
 0101  (negating)
 0110  (adding 1 to get final value)

So it prints it as -110 which is equivalent to -6.

Am I right with this interpretation?

Upvotes: 2

Views: 1882

Answers (2)

Aaron
Aaron

Reputation: 11075

You're half right..

The value is indeed represented by ~x == -(x+1) (add one and invert), but the explanation of why is a little misleading.

Two's compliment numbers require setting the MSB of the integer, which is a little difficult if the number can be an arbitrary number of bits long (as is the case with python). Internally python keeps a separate number (there are optimizations for short numbers however) that tracks how long the digit is. When you print a negative int using the binary format: f'{-6:b}, it just slaps a negative sign in front of the binary representation of the positive value (one's compliment). Otherwise, how would python determine how many leading one's there should be? Should positive values always have leading zeros to indicate they're positive? Internally it does indeed use two's compliment for the math though.

If we consider signed 8 bit numbers (and display all the digits) in 2's compliment your example becomes:

~ 0000 0101:  5
= 1111 1010: -6

So in short, python is performing correct bitwise negation, however the display of negative binary formatted numbers is misleading.

Upvotes: 3

Mark Tolonen
Mark Tolonen

Reputation: 178179

Python integers are arbitrarily long, so if you invert 0b0101, it would be 1111...11111010. How many ones do you write? Well, a 4-bit twos complement -6 is 1010, and a 32-bit twos complement -6 is 11111111111111111111111111111010. So an arbitrarily long -6 could ideally just be written as -6.

Check what happens when ~5 is masked to look at the bits it represents:

>>> ~5
-6
>>> format(~5 & 0xF,'b')
'1010'
>>> format(~5 & 0xFFFF,'b')
'1111111111111010'
>>> format(~5 & 0xFFFFFFFF,'b')
'11111111111111111111111111111010'
>>> format(~5 & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,'b')
'11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111010'

A negative decimal representation makes sense and you must mask to limit a representation to a specific number of bits.

Upvotes: 2

Related Questions