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
我猜想这与数据类型有关,甚至使用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
我没有大学文凭。Sci。发现自己被卡住了(也许这是个骗局)。我尝试过的事情:

  • numpy
    数组具有固定大小。不;似乎表明我应该先点击
    内存错误
  • 我可能有一个32位的安装(可能不相关);没有,我跟踪并确认我有64位
  • 其他怪异的
    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!'