Python sum()在大型数组上给出奇怪的结果
在Python sum()在大型数组上给出奇怪的结果,python,python-2.7,numpy,Python,Python 2.7,Numpy,在numpy数组上使用.sum()似乎发现了一个陷阱,但我找不到解释。从本质上说,如果我尝试对一个大数组求和,那么我会得到一些毫无意义的答案,但这种情况会悄无声息地发生,我无法很好地理解输出的意义,从而用谷歌搜索出原因 例如,这完全符合预期: a = sum(xrange(2000)) print('a is {}'.format(a)) b = np.arange(2000).sum() print('b is {}'.format(b)) 为以下两者提供相同的输出: a is 1999
numpy
数组上使用.sum()
似乎发现了一个陷阱,但我找不到解释。从本质上说,如果我尝试对一个大数组求和,那么我会得到一些毫无意义的答案,但这种情况会悄无声息地发生,我无法很好地理解输出的意义,从而用谷歌搜索出原因
例如,这完全符合预期:
a = sum(xrange(2000))
print('a is {}'.format(a))
b = np.arange(2000).sum()
print('b is {}'.format(b))
为以下两者提供相同的输出:
a is 1999000
b is 1999000
但是,这不起作用:
c = sum(xrange(200000))
print('c is {}'.format(c))
d = np.arange(200000).sum()
print('d is {}'.format(d))
给出以下输出:
c is 19999900000
d is -1474936480
在一个更大的阵列上,有可能得到一个积极的结果。这是更阴险的,因为我可能根本不知道发生了什么不寻常的事情。例如:
e = sum(xrange(100000000))
print('e is {}'.format(e))
f = np.arange(100000000).sum()
print('f is {}'.format(f))
给出了:
e is 4999999950000000
f is 887459712
我猜想这与数据类型有关,甚至使用pythonfloat
似乎也解决了这个问题:
e = sum(xrange(100000000))
print('e is {}'.format(e))
f = np.arange(100000000, dtype=float).sum()
print('f is {}'.format(f))
给予:
e is 4999999950000000
f is 4.99999995e+15
我没有大学文凭。Sci。发现自己被卡住了(也许这是个骗局)。我尝试过的事情:
numpy
数组具有固定大小。不;似乎表明我应该先点击内存错误
sum
行为的例子;没有(?)我找到了,但我看不出它是如何应用的dtype
,还有什么方法可以阻止这种情况发生或发出警告
可能相关:
视窗7
numpy
1.11.3
在Windows上的Python2.7.9(也在64位系统上)上的Enthow Corporation用完了。如果从Python ints转换为32位,则默认整数NumPy使用。在Linux和Mac上,它是64位的
指定一个64位整数,它将工作:
d = np.arange(200000, dtype=np.int64).sum()
print('d is {}'.format(d))
输出:
c is 19999900000
d is 19999900000
虽然不是最优雅的,但您可以使用:
从现在起,arange默认使用64位整数。我不是numpy专家,但可以在纯Python中重现您的
arange(200000)
结果:
>>> s = 0
>>> for i in range(200000):
... s += i
... s &= 0xffffffff
>>> s
2820030816
>>> s.bit_length()
32
>>> s - 2**32 # adjust for that "the sign bit" is set
-1474936480
换句话说,如果numpy
对有符号2的补码32位整数进行运算,您看到的结果就是我所期望的结果
因为我不是
numpy
专家,所以我不能建议一个不感到惊讶的好方法(我会把它作为一个注释,但我当时无法显示格式良好的代码)。这显然是numpy的整数类型溢出32位。通常,您可以使用np.seterr
将numpy配置为在这种情况下失败:
>>> import numpy as np
>>> np.seterr(over='raise')
{'divide': 'warn', 'invalid': 'warn', 'over': 'warn', 'under': 'ignore'}
>>> np.int8(127) + np.int8(2)
FloatingPointError: overflow encountered in byte_scalars
但是,sum
明确记录了行为“溢出时不会出现错误”,因此您可能在这里运气不佳。为了方便起见,使用numpy通常是性能的折衷
但是,您可以手动指定累加器的数据类型,如下所示:
>>> a = np.ones(129)
>>> a.sum(dtype=np.int8) # will overflow
-127
>>> a.sum(dtype=np.int64) # no overflow
129
注意罚单,因为这是一个开放的问题,可能会被numpy开发人员在某个时候修复 Numpy的默认整数类型与C
long
类型相同。现在,在64位平台上不能保证是64位。事实上,在Windows上,long
总是32位
结果,numpy和溢出了值并循环返回
不幸的是,据我所知,无法更改默认的dtype
。每次都必须将其指定为np.int64
您可以尝试创建自己的arange
:
def arange(*args, **kw):
return np.arange(dtype=np.int64, *args, **kw)
然后用那个版本而不是numpy的
编辑:如果要标记此,可以在代码顶部添加类似的内容:
assert np.array(0).dtype.name != 'int32', 'This needs to be run with 64-bit integers!'
可能是因为
numpy
整数依赖于C型整数,而python有无限的整数范围。花车是。。。浮动。它们可能非常高。请检查np.arange(5).dtype
。它可能使用32位整数而不是64位整数。另外,确保在同一个Python安装上执行所有这些检查。看起来像是某种溢出。。。整数的符号似乎也被覆盖了,这可能是您有时会得到否定结果的原因。@user2357112确实它正在打印dtype('int32')
,这对我来说是有意义的,但我的一个关键问题是是否有方法标记它。调试时,这太容易被我忽略了;有没有办法确定我错过了这个?添加了一个可能的解决方案。另请参见,默认使用C long int,Windows将其定义为32位整数,即使在64位CPU上也是如此。从搜索“2的补码”开始。对于不同的固定位宽度(8、16、32、64),这是几乎所有计算机硬件用于表示有符号整数的方案。在像C
这样的低级语言中(CPython和numpy是用这种语言编码的),像这样的本地硬件类型就是您所使用的。要实现Python的无限宽2的补码整数的幻觉,需要很多代码。非常感谢,我现在正在阅读。“封面下的很多代码”屏蔽了我,谢谢:)在这种情况下,维姆在他的回答中链接到了一张公开票,上面写着numpy
;我们已经认识到,在这个特殊的情况下(这让我很吃惊)没有溢出错误,但它已经开放多年了:(非常感谢您将票包括在内。我怀疑这是一个溢出,但由于没有任何警告,我怀疑到底发生了什么。再加上不知道Windows会自动将int转换为32位,这让我感到困惑。
assert np.array(0).dtype.name != 'int32', 'This needs to be run with 64-bit integers!'