我似乎在.sum()
数组上使用numpy
时发现了一个陷阱,但我无法找到解释。从本质上讲,如果我尝试对一个大型数组求和,那么我就会开始得到无意义的答案,但这种情况会发生静默,而且我无法理解输出到谷歌的原因。
例如,这完全符合预期:
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
我猜测这与数据类型有关,甚至使用python float
似乎解决了这个问题:
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
我没有Comp的背景。科学。并发现自己卡住了(也许这是一个骗局)。我尝试过的事情:
答案 0 :(得分:5)
在Windows上(在64位系统上),如果从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
虽然不是最优雅,但您可以使用monkey patching:
执行一些functools.partial
from functools import partial
np.arange = partial(np.arange, dtype=np.int64)
从现在起np.arange
默认使用64位整数。
答案 1 :(得分:4)
这显然是numpy的整数类型溢出32位。通常,您可以使用var jsonObject = data.data;
console.log(jsonObject.ACTION)
np.seterr
但是,>>> 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
明确记录了行为“溢出时不会出现错误”,因此您可能会在此处运气不佳。为方便起见,使用numpy通常是性能的折衷!
但是,您可以手动指定累加器的dtype,如下所示:
sum
观看故障单#593,因为这是一个未解决的问题,有时可能会被numpy devs修复。
答案 2 :(得分:3)
我不是一个笨拙的专家,但可以用纯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
专家,我不能建议一个永远不会感到惊讶的好方法(我会留下这个作为评论,但我无法显示格式良好的代码)。
答案 3 :(得分:2)
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&#39>。
编辑 如果你想标记,你可以在代码的顶部加上这样的内容:
assert np.array(0).dtype.name != 'int32', 'This needs to be run with 64-bit integers!'