python和java之间对负数存储方式的不同
今天在leetcode上刷题时,发现python对于负数的二进制表示和其他有符号语言不同。
计算机如何存储负数
负数在计算机中是以补码的形式存在的,最高位是符号位
以-4为例 (32位整数)
print(bin(-4))
# -0b100
System.out.println(Integer.toBinaryString(-4));
// 11111111111111111111111111111100
当将其他语言的负数表示在python中转化为10进制时
print(int("11111111111111111111111111111100", 2))
# 原本-4 的表示就会变成 4294967292
也就是说python不会理解最高位为符号位
这句话,将上面的二进制当做整数进行转化。正因为这种特性,在位运算时应格外注意负数的情况
解决办法
# 一个补码表示的负数想转化成python理解的负数
# 11111111111111111111111111111100 和 11111111111111111111111111111111 进行 异或运算
print(bin(0b11111111111111111111111111111100 ^ 0xffffffff))
# 0b11
# 再对上述结果进行取反操作 ~ (0变1 1变 0) 这样在计算中符号位会被Python理解为 -数
print(bin(~(0b11111111111111111111111111111100 ^ 0xffffffff)))
# -0b100 即转化成了 Python理解的 负数啦
def toPythonBinMinus(binnumber: int):
# binnumber : without '0b' like 11111111111111111111111111111100
# python 整数没有long这个概念就取最高位判断正数 负数表示
if (str(binnumber)[0] == '1'):
return bin(~(binnumber ^ 0xffffffff))
else:
return f"0b{binnumber}"
算法题
class Solution(object):
def singleNumber(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
res = 0
# 记录符号位的加和
last_pin = 0
for i in range(32):
cur_sum = 0
for num in nums:
cur_sum += (num >> i) & 1
# print(cur_sum)
if cur_sum % 3 == 1:
res |= 1 << i
last_pin = cur_sum
# 这里直接计算出的结果是补码表示的 python 会识别成正整数,所以如果是负数就需要转化成python 的转化方式
#如果符号位加和不能被3整除 证明是 负数的结果 需要进行专门的转化
return res if last_pin % 3 == 0 else ~(res ^ 0xffffffff)