numpy矢量化-很奇怪的问题

时间:2019-02-21 16:10:07

标签: python numpy numpy-ndarray

我正在使用numpy执行一些矢量化计算。我正在调查我遇到的错误,并以这一行结尾:

(vertices[:,:,:,0]+vertices[:,:,:,1]*256)*4

对于索引100728,预期结果为vertices[0,0,17],但是,我得到的是35192。 当我尝试将其更改为4.0而不是4时,我结束了获得正确的100728值,从而解决了我的错误。

我想了解为什么浮点在这里很重要,特别是我使用的是python 3.7,它是乘法,而不是除法。

其他信息:

vertices.shape=(203759, 12, 32, 3)
python==3.7
numpy==1.16.1

编辑1:

  • 顶点类型为“ numpy.uint8”
  • vertices [0,0,17] => [94,98,63]

1 个答案:

答案 0 :(得分:2)

这里的问题是您使用的整数太小,并且数字溢出并回绕,因为numpy使用固定宽度的整数而不是像python int这样的无限精度。 Numpy将根据输入"promote"来确定结果的类型,但不会根据是否发生溢出来提升结果(它是在实际计算之前完成的。

在这种情况下,当您乘以vertices[:,:,:,1]*256(我将其称为A)时,不能在uint8中保留256,因此它将转到下一个更高的类型:{{ 1}}这样,在这种情况下,乘法结果就可以保持正确的值,因为uint16中任何元素的最大可能值为255,因此可能的最大值是255 * 256,正好适合只需16位元。

然后添加verticies(我将其称为vertices[:,:,:,0] + A)。如果B的最大值为255 * 256,并且A的最大值为255(再次为vertices[:,:,:,0]的最大值),则两者的最大和等于2 16 -1(您可以在16位无符号整数中保留的最大值)。直到您进行最后的乘法,这仍然很好。

当您到达uint8时,numpy必须再次确定返回类型应该是什么。整数4很容易容纳在B * 4中,因此numpy不会将类型进一步提升为uint16uint32,因为它不能像前面描述的那样预先避免溢出。这将导致所有大于2 16 -1的乘积以模2 16 的形式返回。

如果您改用浮点数(uint64),则numpy将其视为无法容纳在4. or 4.0内的“较高”值类型,因此将结果提升为浮点数,即可以容纳更多的数字而不会溢出。

如果您不想将整个数组:uint16更改为更大的dtype,则可以简单地将结果verticies转换为4之前将其转换为:{{1 }}。这样一来,您可以保存很多个较大的值而不会溢出(尽管如果该值大于4,则实际上并不能消除问题)。