平方 python 所需的时间

Time it takes to square in python

我想知道 x**2 还是 x*x 更快

def sqr(x):
    for i in range (20):
        x = x**2
    return x
def sqr_(x):
    for i in range (20):
        x = x*x
    return x

当我计时时,这是我得到的:

The time it takes for x**2: 101230500
The time it takes for x*x: 201469200

我试了很多很多次,要么相等,要么x ** 2比x * x快。但是 x*x 永远不会比 x**2 快。

所以我拆解了代码:

对于 x**2:

  5          12 LOAD_FAST                0 (x)
             14 LOAD_CONST               2 (2)
             16 BINARY_POWER
             18 STORE_FAST               0 (x)
             20 JUMP_ABSOLUTE            8

对于 x*x:

  9          12 LOAD_FAST                0 (x)
             14 LOAD_FAST                0 (x)
             16 BINARY_MULTIPLY
             18 STORE_FAST               0 (x)
             20 JUMP_ABSOLUTE            8

是关于 load_const 比 load_fast 稍微快一点吗?

LOAD_CONST: takes the literal value at index 1 of co_consts and pushes it

LOAD_FAST is accessing the value in an array by index

或者binary_power比binary_multiply快(我其实不知道binary_power算法)?

对于小整数,x*xx**2 快得多,因为 CPython 在内部做了更多的操作来计算 a**b。实际上,在我的机器上 x*x 快 4 倍(处理器 i5-9600KF,CPython 3.8.1,在 Windows 上)。话虽如此,在您的代码中,数字增长非常快,并且 Python 整数是无限的。事实上,每次求幂都会使二进制表示变大两倍。指数相乘得到 x**(2*2*2*...*2) = x**(2**20) = x**1048576 的计算结果。对于大 x=2,该数字占用内存 128 KiB,对于 x=100 则占用 850 KiB。这是相当大的。循环的每次迭代都受到内存中如此巨大数字的计算的限制。因此,对于大数,x*xx**2 一样快,因为对这两种情况和 C[= 的开销进行了相同的内部计算57=] 与巨大整数的计算相比,解释器变得可以忽略不计。


引擎盖下

在内部,CPython 似乎使用 _PyNumber_PowerNoMod which calls PyNumber_Power which calls ternary_op, and PyNumber_Multiply which calls binary_op1。请注意,CPython 未针对计算 x**2 进行优化:在内部 CPython 计算 pow(x, 2, None) 这是计算模幂的函数(尽管调用 pow 是一种效率较低的方法,因为 CPython 必须检查 pow 是否未被覆盖)。与 x * x.

相比,此模幂函数要昂贵得多,因为它是一个非常 通用函数

最后,您的情况似乎调用了 long_mul and long_pow(请注意,long_pow 在内部调用 long_mul,因此 long_pow 实际上需要计算更多指令)。

对于大数,CPython 使用 Karatsuba multiplication (see: k_mul).

请注意,CPython 实际上在这两种情况下都非常慢,因为它需要几纳秒(至少在我的机器上)并执行数十次检查和许多函数调用只是为了将两个整数相乘。对于主流 x86-64 处理器上的 64 位整数,这可以仅在 1 个周期内本地完成。大整数不能由主流处理器本地计算,需要更昂贵的计算。