用大数字的Python减法

时间:2017-02-02 01:51:15

标签: python

我正在玩Python中的大数字,我运行了

的计算
2**(1322134) - 2**(1322134)

显然需要很长时间才能计算出来。但是当我运行

的计算时
DataContext = this;

它立即返回0.

如果不进行计算,Python如何自动告诉这些是相同的数字?

3 个答案:

答案 0 :(得分:4)

缓慢的部分是打印数字,而不是计算它:

In [1]: %timeit str(2**1322134)
1 loop, best of 3: 2.28 s per loop

In [2]: %timeit 2**1322134
10000000 loops, best of 3: 24.8 ns per loop

您可以通过将结果存储在变量中来查看:

>>> x = 2**1322134
>>> y = 2**1322134
>>> x - y
0

上述代码将立即执行,因为Python不会在屏幕上打印出近400,000个数字。

答案 1 :(得分:3)

实际上我无法重现这个例子:

i = 1322134
%timeit 2 ** i - 2 ** i  # 10 loops, best of 3: 24.8 ms per loop

花费(大约)两倍的时间

i = 1322134
%timeit 2 ** i  # 100 loops, best of 3: 12.7 ms per loop

取。

有一个例外 - 如果你"硬编码"你的价值:

%timeit 2 ** 1322134  # 10000000 loops, best of 3: 61.5 ns per loop
%timeit 2 ** 1322134 - 2 ** 1322134  # 10000000 loops, best of 3: 61.3 ns per loop

因为Python会计算出这个"常数"当它将它转换为字节码并且只在运行时查找它(几乎是免费的)。

您始终可以通过dis.dis

进行检查来检查Python操作
import dis

def func1():
    return 2 ** 1322134 - 2 ** 1322134

dis.dis(func1)
#  2           0 LOAD_CONST               5 (0)  # just loads the constant
#              3 RETURN_VALUE

def func2():
    i = 1322134
    return 2 ** i - 2 ** i

dis.dis(func2)
#  2           0 LOAD_CONST               1 (1322134)
#              3 STORE_FAST               0 (i)
#
#  3           6 LOAD_CONST               2 (2)
#              9 LOAD_FAST                0 (i)
#             12 BINARY_POWER
#             13 LOAD_CONST               2 (2)
#             16 LOAD_FAST                0 (i)
#             19 BINARY_POWER
#             20 BINARY_SUBTRACT
#             21 RETURN_VALUE

所以func2执行它应该执行的所有指定操作,而func1只是加载并返回已经预先计算的(计算在转换时完成!)值。

如果您想知道为什么显示它需要这么长时间,我认为@Blenders answer是正确的。如果你想显示某些内容,那么Python会将repr(obj)打印到sys.stdout - 所以你有一个案例,其中1个字符(0)被转换为字符串然后打印,另一个案例在哪里需要创建,传递和打印398,002个字符。只是创建repr非常慢:

i = 1322134
%timeit repr(2 ** i - 2 ** i)  # 10 loops, best of 3: 24.7 ms per loop
%timeit repr(2 ** i)           # 1 loop, best of 3: 6.34 s per loop  # <--- whoops that's slow!

答案 2 :(得分:1)

CAVEAT:下面的初步解释是错误的。我把它留在这里作为自我教育和社区工作的一个例子。我通过高级编译器构建的教育和Python内部的部分知识来实现​​它。

----错误的答案----

表达式处理程序内置了优化。减法的表达式求值程序的工作方式如下:

 1. reserve space for first operand:
    2 already exists as a frequently-used small integer
    temp1 = 1322134
    temp2 = 2^(temp1)
 2. reserve space for second operand:
    2 already exists
    13322134 already exists as temp1
    2^(temp1) already exists as temp2
 3. reserve space for the result:
    temp3 = temp2 - temp2
Hey!  That's a really easy operation!
    The result is 0, which already exists as a frequently-used small integer.

----错误的回答----

更多实验

为了测试操作,我进行了这些调整:

  1. 不打印结果;这消除了文本转换时间。
  2. 循环多次以累积实际计算时间。
  3. 更改指数以减少从上一次迭代中缓存结果的可能性。
  4. 代码:

    >>> def pow2(i):
    ...   for _ in range(1000):
    ...      qqq = 2 ** i
    ...      i += 1
    ... 
    >>> def powsub(i):
    ...   for _ in range(1000):
    ...      qqq = 2 ** i - 2 ** i
    ...      i += 1
    ... 
    >>> import time
    j = 987654
    >>> start = time.time(); pow2(j); print time.time() - start
    7.41031980515
    >>> start = time.time(); powsub(j); print time.time() - start
    15.060614109
    

    我还测试了原始循环时间,用RHS 2 替换 qqq 计算。这花了不到一毫秒。

    从此,我观察到了

    1. 相对于控制时间,计算时间很重要:解释器似乎在每个循环中执行计算。
    2. 减法例程需要大约两倍的时间,这表明解释器确实在进行两种计算。
    3. 每个循环的执行时间远远少于执行和打印一次计算的时间。
    4. <强>结论

      我原来的回答是错误。 MSeifert和Blender钉了它。

      我在这里留下这个答案是一个失败的反例。