Numpy 向量化 - 奇怪的问题

Numpy Vectorization - Weird issue

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

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

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

我想了解为什么浮点数在这里很重要,尤其是我使用的是 python 3.7,它是乘法,甚至不是除法。

额外信息:

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

编辑 1:

这里的问题是您使用的整数太小,数字会溢出并环绕,因为 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(又是a的最大值uint8),则两者的最大和等于216-1(您可以在 16 位无符号整数中保存的最大值)。在你进行最后一次乘法之前,这仍然很好。

当你到达 B * 4 时,numpy 必须再次决定 return 类型应该是什么。整数 4 很容易适合 uint16,因此 numpy 不会将类型提升到 uint32uint64,因为它不会像前面描述的那样抢先避免溢出。这导致任何大于 216-1 的乘积被 returned 为模 216.

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

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