How to convert signed to unsigned integer in python

后端 未结 7 1922
攒了一身酷
攒了一身酷 2020-11-29 20:09

Let\'s say I have this number i = -6884376. How do I refer to it as to an unsigned variable? Something like (unsigned long)i in C.

7条回答
  •  执笔经年
    2020-11-29 20:58

    To get the value equivalent to your C cast, just bitwise and with the appropriate mask. e.g. if unsigned long is 32 bit:

    >>> i = -6884376
    >>> i & 0xffffffff
    4288082920
    

    or if it is 64 bit:

    >>> i & 0xffffffffffffffff
    18446744073702667240
    

    Do be aware though that although that gives you the value you would have in C, it is still a signed value, so any subsequent calculations may give a negative result and you'll have to continue to apply the mask to simulate a 32 or 64 bit calculation.

    This works because although Python looks like it stores all numbers as sign and magnitude, the bitwise operations are defined as working on two's complement values. C stores integers in twos complement but with a fixed number of bits. Python bitwise operators act on twos complement values but as though they had an infinite number of bits: for positive numbers they extend leftwards to infinity with zeros, but negative numbers extend left with ones. The & operator will change that leftward string of ones into zeros and leave you with just the bits that would have fit into the C value.

    Displaying the values in hex may make this clearer (and I rewrote to string of f's as an expression to show we are interested in either 32 or 64 bits):

    >>> hex(i)
    '-0x690c18'
    >>> hex (i & ((1 << 32) - 1))
    '0xff96f3e8'
    >>> hex (i & ((1 << 64) - 1)
    '0xffffffffff96f3e8L'
    

    For a 32 bit value in C, positive numbers go up to 2147483647 (0x7fffffff), and negative numbers have the top bit set going from -1 (0xffffffff) down to -2147483648 (0x80000000). For values that fit entirely in the mask, we can reverse the process in Python by using a smaller mask to remove the sign bit and then subtracting the sign bit:

    >>> u = i & ((1 << 32) - 1)
    >>> (u & ((1 << 31) - 1)) - (u & (1 << 31))
    -6884376
    

    Or for the 64 bit version:

    >>> u = 18446744073702667240
    >>> (u & ((1 << 63) - 1)) - (u & (1 << 63))
    -6884376
    

    This inverse process will leave the value unchanged if the sign bit is 0, but obviously it isn't a true inverse because if you started with a value that wouldn't fit within the mask size then those bits are gone.

提交回复
热议问题