简体   繁体   English

如何在 Python 中进行按位 Not 操作?

[英]How do I do a bitwise Not operation in Python?

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.为了测试使用更多基本构建块(使用 Nand、Or 和 And,在我的情况下)构建 Xor 操作,我需要能够执行 Not 操作。 The built-in not only seems to do this with single bits.内置not似乎只与单个位做到这一点。 If I do:如果我做:

x = 0b1100
x = not x

I should get 0b0011 but instead I just get 0b0 .我应该得到0b0011但我只得到0b0 What am I doing wrong?我究竟做错了什么? Or is Python just missing this basic functionality?或者 Python 只是缺少这个基本功能?

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.我知道 Python 有一个内置的 Xor 函数,但我一直在使用 Python 来测试我需要构建 Xor 门的 HDL 项目/课程的东西。 I wanted to test this in Python but I can't without an equivalent to a Not gate.我想在 Python 中测试这个,但我不能没有与 Not 门等效的东西。

The problem with using ~ in Python, is that it works with signed integers.在 Python 中使用~的问题在于它适用于有符号整数。 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对于 4 位逻辑,您应该从0b1111减去

0b1111 - 0b1100  # == 0b0011

For 8 bit logic, subtract from 0b11111111 etc.对于 8 位逻辑,从0b11111111等中减去。

The general form is一般形式是

def bit_not(n, numbits=8):
    return (1 << numbits) - 1 - n

Another way to achieve this, is to assign a mask like this (should be all 1's):实现此目的的另一种方法是分配这样的掩码(应该全为 1):

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.您可以参考异或真值表以了解其工作原理。

Python bitwise '~' operator invert all bits of integer but we can't see native result because all integers in Python has signed representation. Python 按位 '~' 运算符反转整数的所有位,但我们看不到本机结果,因为 Python 中的所有整数都有带符号表示。

Indirectly we can examine that:我们可以间接检查:

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

Or the same:或者一样:

>>> a + ~a
-1

Ther result -1 means all bits are set.结果 -1 表示所有位都已设置。 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.第一种方法是导入 'numpy' 或 'ctypes' 模块,它们都支持无符号整数。 But numpy more simplest using than ctypes (at least for me):但是 numpy 比 ctypes 更简单(至少对我而言):

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: 8 位整数(字节)的无符号整数“255”与“-1”相同,因为所有位都设置为 1。请确保:

>>> 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:另一个最简单的解决方案,不太正确,但如果您想包含其他模块,您可以使用 XOR 操作反转所有位,其中第二个参数将所有位设置为 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

试试这个,它被称为按位补码运算符

~0b1100

string of binary can be used to preserve the left 0s, since we know that:二进制字符串可用于保留左 0,因为我们知道:

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

This function will return string format of the NOT of input number此函数将返回输入数字的 NOT 的字符串格式

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

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() :无需修复 8 位掩码或要求程序员更改掩码中有多少位,只需根据通过bit_length()输入创建掩码:

def bit_not(num):
    return num ^ ((1 << num.bit_length()) - 1)

The general form given by John La Rooy, can be simplified in this way (python == 2.7 and >=3.1): John La Rooy 给出的一般形式,可以这样简化(python == 2.7 and >=3.1):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM