Python、len 和整数的大小

5 投票
3 回答
4644 浏览
提问于 2025-04-15 18:25

所以,cPython(2.4)在处理长度接近1<<32(也就是整数的大小)时,有一些有趣的表现。

r = xrange(1<<30)
assert len(r) == 1<<30

这个是没问题的,但:

r = xrange(1<<32)
assert len(r) == 1<<32
ValueError: xrange object size cannot be reported`__len__() should return 0 <= outcome

Alex的wowrange也有类似的表现。wowrange(1<<32).l是没问题的,但len(wowrange(1<<32))就出问题了。我猜这里可能有一些浮点数的行为(被当作负数处理)在作怪。

  1. 这里到底发生了什么?(下面有比较好的解答!)
  2. 我该如何解决这个问题? 用长整型吗?

(我具体的应用是random.sample(xrange(1<<32),ABUNCH),如果有人想直接解决这个问题!)

3 个回答

1

1<<32 这个表达式,如果把它当作一个有符号的整数来看,结果是负数。

5

你会发现

xrange(1 << 31 - 1)

是最后一个表现得像你想要的那样。这是因为最大带符号的(32位)整数是 2^31 - 1。

1 << 32 不是一个正的带符号32位整数(Python中的 int 数据类型),所以你会遇到那个错误。

在 Python 2.6 中,我甚至不能执行 xrange(1 << 32)xrange(1 << 31) 而不出错,更别提对结果使用 len 了。

补充说明 如果你想要更多细节……

1 << 31 代表的数字是 0x80000000,在二进制补码表示法中,这是一个32位 int 能表示的最小负数(-1 * 2^31)。所以,是的,由于你正在处理的数字的位表示,它实际上变成了负数。

对于一个32位的二进制补码数字,0x7FFFFFFF 是可以表示的最大整数(2^31 - 1),在你“溢出”到负数之前。

如果你感兴趣,可以进一步阅读

注意,当你在提示中看到像 2147483648L 这样的数字时,末尾的 "L" 表示它现在被表示为一个“长整数”(通常是64位,我不能保证 Python 是如何处理的,因为我还没有研究过)。

12

cPython假设列表可以放进内存里。这种假设也适用于那些像列表一样工作的对象,比如xrange。简单来说,len这个函数希望__len__方法返回一个可以转换成size_t的值。如果逻辑上元素的数量太大,即使这些元素实际上并不存在于内存中,这种转换也不会成功。

撰写回答