为什么逐位左移在 Python 和 Java 中返回不同的结果



我正在尝试将某些功能从Java应用程序移植到Python。

在爪哇,

System.out.println(155 << 24);

返回: -1694498816

在 Python 中:

print(155 << 24)

退货2600468480

许多其他按位运算在两种语言中的工作方式相同。为什么这两个操作的结果不同?


编辑:我正在尝试在python中创建一个函数来复制左移运算符在Java中的工作方式。大致如下:

def lshift(val, n):
    return (int(val) << n) - 0x100000000

然而,这似乎不对,因为(我认为)它会将所有数字变为负数?


EDIT2:几个小时后,我决定将Python用于这项工作可能不是最好的主意,并将使用Java应用程序的一部分并将其用作现有Python应用程序的微服务。

Java 有 32 位固定宽度的整数,因此155 << 24155 的最上层设置位(即位 7,从零开始计算位,因为 155 大于2 7 但小于 28)移动到符号位(位 31),最终得到一个负数。

Python 具有任意精度的整数,因此155 << 24在数值上等于正数 155 × 224

这里有 3 种不同的方法可以将 Python 整数转换为其等效的 Java 符号int 。请注意,如果参数宽于 32 位,这些函数将无法正常工作,因此您可能希望在调用它们之前对参数使用位掩码。

第一种方法是使用 struct 模块将数字解释为 32 位无符号整数,将其打包为字节(

使用本地字节序约定),然后解压缩这些字节,将它们解释为 32 位有符号整数。另外两种方法使用简单的算术,没有函数调用,所以它们更快,但我想它们有点难阅读。

这段代码是在运行 Python 2.6.6 的 32 位机器上编写的,但它应该在任何架构和版本的 Python 上都能正常运行(除非它是非常古老的:))。

from __future__ import print_function
from struct import pack, unpack
def ulong_to_long_pack(u):
    ''' using pack & unpack '''
    ubytes = pack('L', u)
    return unpack('l', ubytes)[0]
def ulong_to_long_sub(u):
    ''' using subtraction '''
    return u - (1<<32) if u >= (1<<31) else u
def ulong_to_long2_xor(u):
    ''' using exclusive OR '''
    return u ^ ~((1<<32)-1) if u & (1<<31) else u
funcs = (ulong_to_long_pack, ulong_to_long_sub, ulong_to_long2_xor)
# test
for ulong_to_long in funcs:
    print(ulong_to_long.__doc__)
    u = 2600468480
    print(u, ulong_to_long(u))
    big = 1<<31
    for u in range(big - 3, big + 3):
        print(u, ulong_to_long(u))
    print()

输出

 using pack & unpack 
2600468480 -1694498816
2147483645 2147483645
2147483646 2147483646
2147483647 2147483647
2147483648 -2147483648
2147483649 -2147483647
2147483650 -2147483646
 using subtraction 
2600468480 -1694498816
2147483645 2147483645
2147483646 2147483646
2147483647 2147483647
2147483648 -2147483648
2147483649 -2147483647
2147483650 -2147483646
 using exclusive OR 
2600468480 -1694498816
2147483645 2147483645
2147483646 2147483646
2147483647 2147483647
2147483648 -2147483648
2147483649 -2147483647
2147483650 -2147483646

在java中使用long以获得相同的结果

System.out.println(155L << 24);

而不是

System.out.println(155 << 24);

Long 是 4 字节长度,因此此上下文的精度与 python 整数相同。

最新更新