当我为给定的dtype设置太大的值时会发生什么?

时间:2014-04-27 11:35:06

标签: python numpy

所以我总是创建那样的numpy数组:

>>> u = np.zeros( 10, int )
>>> v = np.zeros( 10, float )

到目前为止,我一直忘记了最大允许值。我一直认为它会起作用。如果没有,我会得到OverflowError,然后我会找到一些解决方法,比如采用对数。

但最近我开始使用其他dtypes:

>>> v8 = np.zeros( 10, np.uint8 )
>>> v8[0] = 2 ** 8 - 1
>>> v8[1] = 2 ** 8
>>> v8
>>> array([255,   0,   0,   0,   0,   0,   0,   0,   0,   0], dtype=uint8)

好的,所以当我指定一个大于255的值时,我不会收到任何警告。这有点可怕。

所以我的问题是:

  • 当我使用类型为intfloat的数组时,是否有可能在不知情的情况下设置一个太大的值(导致完全错误的计算)?
  • 如果我想使用uint8,是否必须手动检查[ 0, 255 ]中所有已分配的值?

4 个答案:

答案 0 :(得分:1)

numpy在机器级别非常深入。测试非常耗时,因此测试由开发人员完成。 Python更高级,许多测试都是自动完成的,或者在整数的情况下,int可以有任意大的值。你必须在任何地方决定速度和安全性。 numpy在速度方面更远。

在需要测试值范围的情况下,您必须自己检查。

剪辑 - 方法可以帮助您:

>>> u = np.array([124,-130, 213])
>>> u.astype('b')
array([124, 126, -43], dtype=int8)
>>> u.clip(-128,127).astype('b')
array([ 124, -128,  127], dtype=int8)

答案 1 :(得分:1)

正如其他答案中所解释的那样,过大的值会被包裹起来,因此您需要在转换之前手动将它们剪切到最小和最大允许值。对于整数,可以使用np.iinfo获得这些限制。您可以编写自己的实用程序函数,以安全的方式对给定的dtype执行此转换:

def safe_convert(x, new_dtype):
    info = np.iinfo(new_dtype)
    return x.clip(info.min, info.max).astype(new_dtype)

快速测试:

In [31]: safe_convert(np.array([-1,0,1,254,255,256]), np.uint8)
Out[31]: array([  0,   0,   1, 254, 255, 255], dtype=uint8)

In [32]: safe_convert(np.array([-129,-128,-127,126,127,128]), np.int8)
Out[32]: array([-128, -128, -127,  126,  127,  127], dtype=int8)

答案 2 :(得分:0)

是的,uint8将掩盖你的值(取8 lsb),所以你需要手动检查它:

>>> a = numpy.uint8(256)
>>> a
0

是的,如果没有你意识到,溢出就会发生。它是许多编程语言中常见的错误来源。但是,python中的长整数以不常见的方式运行:它们没有明确定义的限制。

我在this answer写过这篇文章。

答案 3 :(得分:0)

正如已经解释的那样,numpy包裹起来以避免做检查。

如果剪辑不可接受,则在投射之前,您可以使用numpy.min_scalar_type获取保存数据的最小dtype而不会丢失数据。

另请注意,实际上使用uint8的唯一原因是将内存保存在非常大的数组中,因为计算速度通常大致相同(在某些操作中,内部会向内转换,甚至)。如果您的阵列不是太大而内存不是一个大问题,那么您应该更安全并使用uint16甚至uint32进行中间计算。如果内存是你的问题,你应该考虑转移到核心存储,如PyTables;如果您现在要填补内存,可能使用更大的数据集,即使uint8也不够。