在将int添加到uint8时发生奇怪的类型转换?

5

我有些困惑Python/NumPy在类型转换无符号整数时的工作方式。

例子:

import numpy as np
x = np.array([255], dtype=np.uint8)
y = x + 1

这将得到结果:
In[0]: y
Out[0]: array([0], dtype=uint8)

我了解uint8无法存储大于255的整数,因此会循环回零。我有点预料到这一点。

现在我尝试:

z = x + 256

这意味着:

In[1]: z
Out[1]: array([511], dtype=uint16)

在这种情况下,类型已更改为具有更多字节以容纳更大数字的类型,但仅当要添加的整数本身不适合较小的类型时才会发生。 (有趣的是,x + 255不会产生uint16结果)

这让我感到有些奇怪。 这背后是否有任何逻辑? 我认为一个更一致的做法是在第一个示例案例中也将类型更改为uint16。


256不能表示为uint8。 - adrianN
255 + 1也不是,那么为什么会发生这种情况呢? - JesseC
1
似乎numpy正在查看操作数的大小,而不是结果的大小。这是一个有趣的问题。 - Mark Ransom
1
更奇怪的是,type(np.uint8(511) + 1) 打印出 <type 'numpy.int64'>。它几乎肯定对操作数进行了某种类型强制转换,但我还没有在源代码中找到确切的逻辑。testing/print_coercion_tables.py 中有一个脚本可能会引起兴趣。 - Aya
1个回答

5
这种行为似乎源于一个可理解的愿望,即尽可能减少数组转换。请考虑以下内容:
z = np.uint8(255)
z + 1
# 256
type(z+1)
# numpy.int64

在这种情况下,字面值1的类型为int。看起来在这种情况下,两个操作数都会被强制转换为np.int64。但是这与结果无关!
zz = np.uint8(1)
type(zz + 1)
# numpy.int64

如果我们使用数组而不是一个简单的整数,那么转换的方式就有所不同。
x = np.array([255], dtype=np.uint8)
x + 1
# array([0], dtype=uint8)

在我看来,这可能是因为将整个数组从一种类型转换为另一种类型需要大量的计算工作,因此只有在它确信这将是必要的之前,才会执行此操作,即仅当其他运算数本身不适合当前类型时才会执行。实际上,即使我们考虑到

b = np.int16(1)
x+b
# array([0], dtype=uint8)

因此,实际上它将右操作数转换为较小的类型,以节省数组的类型。另一方面,当两个np.arrays相加时,类型转换总是会转换为较大的类型。

长话短说: - 简单整数加法总是强制转换为操作数的较大类型 - numpy数组和整数相加,如果这足以表示整数,则转换为数组类型,否则转换为整数类型 - 两个numpy数组相加会将其转换为操作数的较大类型(与两个整数相同)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接