python 整数逆位运算_在python中对二进制运算求反的整数的好方法是什么?

Based on what I've read about the binary representation of integers, the first bit is for sign (positive or negative).

Let's say we have an integer x = 5 and sys.getsizeof(x) returns 28 (that is binary representation in 28 bit).

For now I am trying to flip the first bit to 1 by using x|=(1<<27)but it returns 134217733.

I was just wondering whether it needs to be some negative number? (not -5)

Is there anything wrong with what I am doing?

解决方案

You can't switch a Python int from positive to negative the way you're trying to, by just flipping a bit in its representation. You're assuming it's stored in a fixed-length two's complement representation. But integers in Python 3 are not fixed-length bit strings, and they are not stored in a two's complement representation. Instead, they are stored as variable-length strings of 30- or 15-bit "digits", with the sign stored separately (like a signed-magnitude representation). So the "lowest-level" way to negate a Python int is not with bit operations, but with the unary - operator, which will switch its sign. (See the end of this answer for details from the Python 3 source.)

(I should also mention that sys.getsizeof() does not tell you the number of bits in your int. It gives you the number of bytes of memory that the integer object is using. This is also not the number of bytes of the actual stored number; most of those bytes are for other things.)

You can still play around with two's complement representations in Python, by emulating a fixed-length bit string using a positive int. First, choose the length you want, for example 6 bits. (You could just as easily choose larger numbers like 28 or 594.) We can define some helpful constants and functions:

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

Now we can do something like you were trying to:

>>> x = to2c(2)

>>> x |= 1 << 5

>>> bin(x)

'0b100010'

>>> from2c(x)

-30

Which shows that turning on the high bit for the number 2 in a 6-bit two's complement representation turns the number into -30. This makes sense, because 26-1 = 32, so the lowest integer in this representation is -32. And -32 + 2 = -30.

If you're interested in the details of how Python 3 stores integers, you can look through Objects/longobject.c in the source. In particular, looking at 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);

}

you can see that all it does in the normal case is negate the Py_SIZE() value of the integer object. Py_SIZE() is simply a reference to the ob_size field of the integer object. When this value is 0, the integer is 0. Otherwise, its sign is the sign of the integer, and its absolute value is the number of 30- or 15-bit digits in the array that holds the integer's absolute value.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值