我正在使用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:
答案 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不会将类型进一步提升为uint16
或uint32
,因为它不能像前面描述的那样预先避免溢出。这将导致所有大于2 16 -1的乘积以模2 16 的形式返回。
如果您改用浮点数(uint64
),则numpy将其视为无法容纳在4. or 4.0
内的“较高”值类型,因此将结果提升为浮点数,即可以容纳更多的数字而不会溢出。
如果您不想将整个数组:uint16
更改为更大的dtype,则可以简单地将结果verticies
转换为4之前将其转换为:{{1 }}。这样一来,您可以保存很多个较大的值而不会溢出(尽管如果该值大于4,则实际上并不能消除问题)。