Python 对于 1 的左移和 2 的幂的行为不同

Python behaves differently for left shift of 1 and power of 2

我试图在我的系统上计算 1 << sys.maxsize,python 立即给了我一个 内存错误但是当我尝试做 2 ** maxsize python 开始计算它时没有任何内存错误。 尽管 1 << a 等同于 2 ** a。 (对于所有正 a) 为什么会有这种行为?

案例 1:

import sys
1 << sys.maxsize

案例 2:

import sys
2 ** sys.maxsize

案例 1 的结果:

---------------------------------------------------------------------------
MemoryError                               Traceback (most recent call last)
<ipython-input-41-0d82f9d0b2eb> in <module>()
----> 1 1 << sys.maxsize

MemoryError: 

案例 2 的结果:

# This kept on going without any memory error

这两个操作在产生相同结果的方式上是等价的。

>>> import sys, math
>>> sys.maxsize, (sys.maxsize + 1) // 8, math.log((sys.maxsize + 1) // 8, 1024)
(9223372036854775807, 1152921504606846976, 6.0)

如上所示,2 个操作中的 none 是有意义的,因为(在 64 位 上)结果需要 1 EiB (exbibyte) 即 1048576 (> 一百万) TiB (tebibytes) !!!,所以它们都会 运行 内存不足。

根据[Python 3.docs]: Built-in Types - Numeric Types — int, float, complex

Integers have unlimited precision.

在(C)源码中,Pythonint 值表示为 unsigned short [] (longintrepr.h),这两个函数是 long_lshiftlong_pow ([GitHub]: python/cpython - (master) cpython/Objects/longobject.c).

这是 2 个函数的工作原理(简化版):

  • lshift:尝试分配所需的字节来保存 final 结果 - 失败(几乎立即)
  • pow:执行连续乘法,增加中间结果所需的space(你可以发出2 ** sys.maxsize 并查看 任务管理器 中使用的内存如何增长,如果 Ctrl + BreakPython console,内存会下降)。
    乘法是一种昂贵的(CPU 和时间方面的)操作(即使它有加速),还涉及内存分配/复制操作,所以给定足够的时间,中间结果会增长,直到它不适合最大的可用内存块,因此它会失败(有同样的错误)

我不确定为什么数字 2(作为基础),2nd 函数不只是简单地调用 1st 一个,但我想一个额外的 if 子句不会证明(它会引入所有其他数字的开销很小并且)没有人会/应该使用如此大的指数。