为什么Python在所有领域不处理非常大的数字?

5 投票
2 回答
9728 浏览
提问于 2025-04-17 10:53

我正在做一个难题,需要处理10的18次方这么大的数字。不过,我发现Python在某些地方处理非常大的数字时有点问题。

具体来说,如果我把a设为1000000000000000000(也就是10的18次方),然后进行基本的加减乘除运算,它是可以正常工作的。但是,当我在range()函数中使用这个数字时,就会出现OverflowError的错误。

>>> a = 1000000000000000000
>>> a/2
500000000000000000L
>>> a*2
2000000000000000000L
>>> a+a
2000000000000000000L
>>> a*a
1000000000000000000000000000000000000L
>>> range(a)

Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    range(a)
OverflowError: range() result has too many items
>>> xrange(a)

Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    xrange(a)
OverflowError: Python int too large to convert to C long

我使用的是Python 2.7。

  1. 我该如何处理这种情况呢?有什么好的方法来解决包含这样大数字的难题吗?(如果能推荐一些教程或书籍就更好了)
  2. 为什么Python在range()/xrange()中处理不了这么大的数字呢?

我希望能在Python 2.7中使用内置函数来实现这个功能。这不是不可能吧?

2 个回答

1

你的问题在于,Python 2.7中的range()函数会生成一个包含范围内每个值的完整列表——这需要的资源太多了,你的设备可能承受不了。

Python 3对此进行了改进,它只在需要的时候计算值,就像使用生成器表达式一样。

Python 2中的xrange()函数也帮不了你,因为它只能记录一些值……这是Python 2为了避免range()在处理较大数字时消耗过多资源而做出的妥协。

一种解决方法是自己定义一个生成器,可以遍历任意整数,像这样:

def genrange(min,max,stride=1):
    val=min
    while val<max:
        yield val
        val+=stride

不过我怀疑,这可能在更大的问题上是个错误——因为你不太可能有足够的处理资源去遍历所有32位整数的每个值,更不用说超过32位寄存器的整数范围了。我觉得还有更好的方法来解决你的问题,而不需要依赖于范围。

10

在Python 2.x中,rangexrange的使用受到限制,只能处理C语言中的long类型,而你的大整数可能超出了这个范围。这种限制是因为rangexrange的实现方式所决定的。

而在Python 3.x中,这个限制被取消了,你可以使用range()来处理非常大的整数。

>>> range(2**128)
range(0, 340282366920938463463374607431768211456)

关于Python 3的变化,官方文档是这么说的:

range()现在的表现就像以前的xrange(),不过它可以处理任意大小的值。而xrange()已经不再存在了。


在Python 2.x中,range()函数返回的是一个列表。显然,对于非常大的范围,分配内存来存储所有元素是不现实的。xrange()函数返回的是一个xrange对象。文档中将其描述为“一个不透明的序列类型,它产生与对应列表相同的值,但并不同时存储所有这些值”。文档还提到:

xrange()的设计目标是简单和快速。实现可能会施加一些限制来达到这个目标。Python的C语言实现限制所有参数为本地的C长整型(“短”Python整数),并且要求元素的数量也要适合本地的C长整型。

这就解释了Python 2.x中的限制。


我不太确定在Python 3中对非常大范围的支持可以用来做什么有用的事情。例如,我不建议你尝试这样做:

2**128 in range(2**128)

这会运行很长时间。


你在评论中提到你正在写代码来计算一个大数字。你可以用这样的代码轻松实现:

i = 0
while i<N:
    doSomething(i)
    i += 1

但是你会发现,如果N是一个很大的数字,那么这会花费很长时间。对于像你提问中提到的218这样的N值,这是无法避免的。

撰写回答