Numpy Vectorization - 奇怪的问题

问题描述 投票:0回答:1

我正在使用numpy进行一些矢量化计算。我正在调查我遇到的一个错误,并以此行结束:

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

预计结果将是100728指数vertices[0,0,17],但是,我得到35192。当我试图将它改为4.0而不是4时,我结束了100728的正确值,从而修复了我的bug。

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

额外的信息:

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

编辑1:

  • 顶点类型是“numpy.uint8”
  • 顶点[0,0,17] => [94,98,63]
python numpy numpy-ndarray
1个回答
2
投票

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

在这种情况下,当你乘以:vertices[:,:,:,1]*256(我将称之为A)时,256不能保存在uint8中,因此它转到下一个更高的类型:uint16这允许乘法的结果在这种情况下保持正确的值,因为verticies中任何元素的最大可能值是255,所以可能的最大值是255 * 256,这在16位uint中很合适。

然后你添加vertices[:,:,:,0] + A(我将称之为B)。如果A的最大值是255 * 256,并且vertices[:,:,:,0]的最大值是255(再次是uint8的最大值),则两者中的最大值等于216-1(您可以容纳的最大值) 16位无符号int)。直到你进行最后一次乘法,这仍然很好。

当你到达B * 4时,numpy必须再决定返回类型应该是什么。整数4很容易适合uint16,因此numpy不会将更高的类型提升为uint32uint64,因为它不会先发制人地避免溢出,如前所述。这导致任何大于216-1的乘法乘积作为模216返回。

如果您改为使用浮点数(4. or 4.0),numpy将其视为“更高”的值类型,无法放入uint16中,因此它将结果提升为浮点数,这可以容纳更高的数字而不会溢出。

如果你不想改变整个数组:verticies到一个更大的dtype,你可以简单地取结果B并在你乘以4之前转换它:B.astype(np.uint64) * 4。这将允许您保持更大的值而不会溢出(尽管如果值大于4,它实际上不会消除问题)。

© www.soinside.com 2019 - 2024. All rights reserved.