为什么 (2^31) >> 32 不是 0?

Why is (2^31) >> 32 not 0?

我的问题是

np.array([2**31], dtype=np.uint32) >> 32

不是 return 0,而是 return array([2147483648], dtype=uint32)

也是如此
np.right_shift(np.array([2**31], dtype=np.uint32), 32)

(所以我相信这就是 >> 的实现方式)。

有趣的是,所有这些替代方案似乎都按预期工作,return某种 0:

print(
    2**31 >> 32,
    np.uint32(2**31) >> 32,
    np.array(2**31, dtype=np.uint32) >> 32,
    np.right_shift(2**31, 32),
    np.right_shift([2**31], 32),
    np.right_shift(np.uint32(2**31), 32),
    np.right_shift(np.array(2**31, dtype=np.uint32), 32),
)

特别是,表示 2147483648[2147483648] 的 Numpy 数组有何不同?

我在 JavaScript (Why does << 32 not result in 0 in javascript?) and C++ (Weird behavior of right shift operator (1 >> 32), ) 中看到过这个问题,但在 Python/Numpy 中还没有看到。事实上,Python 和 Numpy 文档似乎都没有记录这种行为:

虽然没有记录,但 numpy 主要是在 C 中实现的,并且 C(和 C++)中的移位运算符没有为大于或等于位数的移位定义。所以结果可以是任意的。

如果您查看有效示例的类型,您就会明白它们为何有效:

print(
    type(2**31 >> 32),
    type(np.uint32(2**31) >> 32),
    type(np.array(2**31, dtype=np.uint32) >> 32),
    type(np.right_shift(2**31, 32)),
    np.right_shift([2**31], 32).dtype,
    type(np.right_shift(np.uint32(2**31), 32)),
    type(np.right_shift(np.array(2**31, dtype=np.uint32), 32)),
)

<class 'int'> <class 'numpy.int64'> <class 'numpy.int64'> <class 'numpy.int64'> int64 <class 'numpy.int64'> <class 'numpy.int64'>

第一个使用 Python 自己的 int 类型,而其他的都转换为 numpy.int64,其中 32 位移位的行为是正确的。 这主要是由于标量(零维)数组的行为不同。在 list 的情况下,numpy 的默认整数类型是 not numpy.uint32.

另一方面

print((np.array([2**31], dtype=np.uint32) >> 32).dtype)

uint32

所以你运行进入这里的未定义行为。