根据我读到的内容 the binary representation of integers ,第一位表示符号(正或负)。
假设我们有一个整数 x = 5
和sys.getsizeof(x)
返回28
(即 28 位的二进制表示)。
现在我正在尝试将第一位翻转为 1
通过使用x|=(1<<27)
但它返回 134217733
.
我只是想知道它是否需要是负数? (不是-5)
我所做的事情有什么问题吗?
最佳答案
您无法通过仅翻转其表示形式中的一点来将 Python int
从正数切换为负数。您假设它存储在固定长度的二进制补码表示形式中。但Python 3 中的整数不是固定长度的位字符串,并且它们不以二进制补码表示形式存储。相反,它们存储为 30 位或 15 位“数字”的可变长度字符串,符号单独存储(如 signed-magnitude representation )。因此,对 Python int
求反的“最低级别”方法不是使用位运算,而是使用一元 -
运算符,该运算符将切换其符号。 (有关 Python 3 源代码的详细信息,请参阅本答案的末尾。)
(我还应该提到 sys.getsizeof()
不会告诉您 int
中的位数。它为您提供整数所占用的内存字节数对象正在使用。这也不是实际存储的字节数;大部分字节用于其他用途。)
您仍然可以在 Python 中使用二进制补码表示形式,方法是使用正 int
模拟固定长度的位字符串。首先,选择您想要的长度,例如 6 位。 (您可以轻松选择更大的数字,例如 28 或 594。)我们可以定义一些有用的常量和函数:
BIT_LEN = 6
NUM_INTS = 1 << BIT_LEN # 0b1000000
BIT_MASK = NUM_INTS - 1 # 0b111111
HIGH_BIT = 1 << (BIT_LEN - 1) # 0b100000
def to2c(num):
"""Returns the two's complement representation for a signed integer."""
return num & BIT_MASK
def from2c(bits):
"""Returns the signed integer for a two's complement representation."""
bits &= BIT_MASK
if bits & HIGH_BIT:
return bits - NUM_INTS
现在我们可以做一些像您试图做的事情:
>>> x = to2c(2)
>>> x |= 1 << 5
>>> bin(x)
'0b100010'
>>> from2c(x)
-30
这表明,在 6 位二进制补码表示中打开数字 2 的高位会将数字变成 -30。这是有道理的,因为 26-1 = 32,因此该表示形式中的最小整数是 -32。 -32 + 2 = -30。
如果您对 Python 3 如何存储整数的详细信息感兴趣,可以查看 Objects/longobject.c在源中。特别是查看the function _PyLong_Negate()
:
/* If a freshly-allocated int is already shared, it must
be a small integer, so negating it must go to PyLong_FromLong */
Py_LOCAL_INLINE(void)
_PyLong_Negate(PyLongObject **x_p)
{
PyLongObject *x;
x = (PyLongObject *)*x_p;
if (Py_REFCNT(x) == 1) {
Py_SIZE(x) = -Py_SIZE(x);
return;
}
*x_p = (PyLongObject *)PyLong_FromLong(-MEDIUM_VALUE(x));
Py_DECREF(x);
}
您可以看到,在正常情况下它所做的只是对整数对象的 Py_SIZE()
值取反。 Py_SIZE()
只是对整数对象的 ob_size
字段的引用。当该值为0时,整数为0。否则,其符号为整数的符号,其绝对值为保存该整数绝对值的数组中30位或15位数字的个数。
关于python - 在 python 中,在二进制运算中对整数取反的好方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37135106/