平方 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*x
比 x**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*x
和 x**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 个周期内本地完成。大整数不能由主流处理器本地计算,需要更昂贵的计算。
我想知道 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*x
比 x**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*x
和 x**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 个周期内本地完成。大整数不能由主流处理器本地计算,需要更昂贵的计算。