Python大数减法

2024-04-20 15:28:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我在Python中处理大量的数字,然后计算

2**(1322134)  

很明显,这需要很长时间来计算。但是当我计算

^{pr2}$

它立即返回0。在

Python如何在不进行计算的情况下自动判断这些数字是相同的?在


Tags: 情况数字pr2
3条回答

注意:下面的最初解释是错误的。我把它作为一个自我教育和社区工作的例子留在这里。我是通过接受高级编译器构造的教育以及对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. 更改指数以减少缓存上一次迭代的结果的可能性。在

代码:

^{pr2}$

我还测试了原始循环时间,将qqq计算替换为RHS2。用了不到一毫秒的时间。

从这一点,我观察到

  1. 相对于控制时间,计算时间很重要:解释器似乎在每个循环中执行计算。在
  2. 减法例程所用的时间是原来的两倍,这表明解释器确实在进行这两种计算。在
  3. 每个循环的执行时间远小于执行和打印一次计算的时间。在

结论

我最初的回答是错的。 姆塞弗特和搅拌机把它钉住了。

我把这个答案留作一个失败的反例。

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

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

用了(大约)两倍的时间

^{pr2}$

需要。

有一个例外-如果您“硬编码”您的值:

%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只加载并返回已经预先计算好的(计算是在转换时完成的!)价值观。


如果你想知道为什么要花这么长时间来显示它,我认为^{}s answer是正确的。如果您想显示某些内容,那么Python会将repr(obj)打印到sys.stdout-因此有一种情况,其中1个字符(0)转换为字符串,然后进行打印;另一种情况下,需要创建、传递和打印398002个字符。仅仅创建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!

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

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

通过将结果存储在变量中可以看到:

^{pr2}$

上面的代码将立即执行,因为Python不必在屏幕上打印出近40万个数字。

相关问题 更多 >