numpy.sum()在大型数组上给出奇怪的结果

时间:2017-01-17 19:52:00

标签: python python-2.7 numpy

我似乎在.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的背景。科学。并发现自己卡住了(也许这是一个骗局)。我尝试过的事情:

  1. numpy数组具有固定大小。不; this似乎表明我应先点击MemoryError
  2. 我可能会以某种方式安装32位(可能不相关);不,我跟着this并确认我有64位。
  3. 奇怪的sum行为的其他例子; nope()我找到了this,但我看不出它是如何适用的。
  4. 有人可以简要解释一下我缺少什么并告诉我需要阅读的内容吗?此外,除了记住每次定义dtype之外,有没有办法阻止这种情况发生或发出警告?

    可能相关:

    Windows 7

    numpy 1.11.3

    在Python 2.7.9上耗尽了Enthought Canopy

4 个答案:

答案 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)

在这种情况下将numpy配置为失败
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!'