当计算的输入是具有32位整数数据类型的numpy数组,但输出包含需要64位表示形式的较大数字时,我遇到了不正确的numpy计算问题。
这是一个最小的工作示例:
arr = np.ones(5, dtype=int) * (2**24 + 300) # arr.dtype defaults to 'int32'
# Following comment from @hpaulj I changed the first line, which was originally:
# arr = np.zeros(5, dtype=int)
# arr[:] = 2**24 + 300
single_value_calc = 2**8 * (2**24 + 300)
numpy_calc = 2**8 * arr
print(single_value_calc)
print(numpy_calc[0])
# RESULTS
4295044096
76800
期望的输出是numpy数组包含正确的值4295044096,这需要64位来表示它。即我希望numpy数组在输出需要时自动将其从int32转换为int64,而不是保持32位输出并在超过2 ^ 32的值后换回0。
当然,我可以通过强制使用int64表示来手动解决问题:
numpy_calc2 = 2**8 * arr.astype('int64')
但这对于一般代码来说是不希望的,因为在某些情况下(并非全部),输出仅需要64位表示(即,保存大量数字)。在我的用例中,性能至关重要,因此每次都强制进行上转换将是昂贵的。
这是numpy数组的预期行为吗?如果是的话,请问有没有一个干净,高效的解决方案?
numpy中的类型转换和升级相当复杂,有时会令人惊讶。塞巴斯蒂安·伯格(Sebastian Berg)最近的一次非正式论文解释了该主题的一些细微差别(主要集中在标量和0d数组)。
引用此文档:
Python整数和浮点数
请注意,python整数的处理方式与numpy的处理方式完全相同。但是,它们的特殊之处在于它们没有显式关联的dtype。如此处所述,基于值的逻辑对于python整数和浮点数允许使用似乎很有用:
arr = np.arange(10, dtype=np.int8) arr += 1 # or: res = arr + 1 res.dtype == np.int8
这样可以确保不会发生上流(例如,内存使用率更高)的情况。
(强调我的。)
另请参见艾伦·霍尔丹(Allan Haldane)提出的C风格强制性要点,该链接来自上一文档:
当前,当二进制操作涉及两个dtype时,numpy的原则是“输出dtype的范围涵盖两个输入dtype的范围”,而当涉及单个dtype时,则永远不会进行任何强制转换。
(再次强调我的。)
因此,我的理解是,numpy标量和数组的提升规则不同,主要是因为检查数组中的每个元素以确定是否可以安全地进行转换是不可行的。再次从以前的文件:
基于标量的规则
与数组不同,在数组中无法检查所有值,对于标量(和0-D数组),将检查值。
这意味着您可以np.int64
从一开始就使用起来是安全的(如果您使用的是Linux,那么dtype=int
实际上将自己进行此操作),或者在进行可疑操作之前检查阵列的最大值,并确定是否必须升级根据具体情况自行确定dtype。我知道,如果您要进行大量计算,这可能不可行,但是我认为考虑numpy当前的类型提升规则,这是没有办法的。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句