How do I do a bitwise Not operation in Python?

Question:

In order to test building an Xor operation with more basic building blocks (using Nand, Or, and And in my case) I need to be able to do a Not operation. The built-in not only seems to do this with single bits. If I do:

x = 0b1100
x = not x

I should get 0b0011 but instead I just get 0b0. What am I doing wrong? Or is Python just missing this basic functionality?

I know that Python has a built-in Xor function but I’ve been using Python to test things for an HDL project/course where I need to build an Xor gate. I wanted to test this in Python but I can’t without an equivalent to a Not gate.

Asked By: Lauren

||

Answers:

Try this, it’s called the bitwise complement operator:

~0b1100
Answered By: Óscar López

The problem with using ~ in Python, is that it works with signed integers. This is also the only way that really makes sense unless you limit yourself to a particular number of bits. It will work ok with bitwise math, but it can make it hard to interpret the intermediate results.

For 4 bit logic, you should just subtract from 0b1111

0b1111 - 0b1100  # == 0b0011

For 8 bit logic, subtract from 0b11111111 etc.

The general form is

def bit_not(n, numbits=8):
    return (1 << numbits) - 1 - n
Answered By: John La Rooy

The general form given by John La Rooy, can be simplified in this way (python == 2.7 and >=3.1):

def bit_not(n):
    return (1 << n.bit_length()) - 1 - n
Answered By: consultit

Another way to achieve this, is to assign a mask like this (should be all 1’s):

mask = 0b1111

Then xor it with your number like this:

number = 0b1100
mask = 0b1111
print(bin(number ^ mask))

You can refer the xor truth table to know why it works.

Answered By: PKBEST

Python bitwise ~ operator invert all bits of integer but we can’t see native result because all integers in Python has signed representation.

Indirectly we can examine that:

>>> a = 65
>>> a ^ ~a
-1

Or the same:

>>> a + ~a
-1

Ther result -1 means all bits are set. But the minus sign ahead don’t allow us to directly examine this fact:

>>> bin(-1)
'-0b1'

The solution is simple: we must use unsigned integers.
First way is to import numpy or ctypes modules wich both support unsigned integers. But numpy more simplest using than ctypes (at least for me):

import numpy as np
a = np.uint8(0b1100)
y = ~x

Check result:

>>> bin(x)
'0b1100'
>>> bin(y)
'0b11110011'

And finally check:

>>> x + y
255

Unsigned integer ‘255’ for 8-bits integers (bytes) mean the same as ‘-1’ becouse has all bits set to 1. Make sure:

>>> np.uint8(-1)
255

And another simplest solution, not quite right, but if you want to include additional modules, you can invert all bits with XOR operation, where second argument has all bits are set to 1:

a = 0b1100
b = a ^ 0xFF

This operation will also drop most significant bit of signed integer and we can see result like this:

>>> print('{:>08b}'.format(a))
00001100
>>> print('{:>08b}'.format(b))
11110011

Finally solution contains one more operation and therefore is not optimal:

>>> b = ~a & 0xFF
>>> print('{:>08b}'.format(b))
11110011
Answered By: An0ther0ne

string of binary can be used to preserve the left 0s, since we know that:

bin(0b000101) # '0b101'
bin(0b101)    # '0b101'

This function will return string format of the NOT of input number

def not_bitwise(n):
     ''' 
     n: input string of binary number (positive or negative)
     return: binary number (string format)
     '''
     head, tail = n.split('b')
     not_bin = head+'b'+tail.replace('0','a').replace('1','0').replace('a','1')
     return not_bin

Example:

In[266]: not_bitwise('0b0001101')
Out[266]: '0b1110010'

In[267]: int(not_bitwise('0b0001101'), 2)

Out[267]: 114

In[268]: not_bitwise('-0b1010101')

Out[268]: '-0b0101010'

In[269]: int(not_bitwise('-0b1010101'), 2)
Out[269]: -42
Answered By: imanzabet

The answers here collectively have great nuggets in each one, but all do not scale well with depending on edge cases.

Rather than fix upon an 8-bit mask or requiring the programmer to change how many bits are in the mask, simply create a mask based on input via bit_length():

def bit_not(num):
    return num ^ ((1 << num.bit_length()) - 1)
Answered By: Flair
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.