Why is 2 * x * x faster than 2 * ( x * x ) in Python 3.x, for integers?
Python整数倍频3.x下面以在线和1.77s:平均1.66s betweenP></
1 2 3 4 5 6 7 | import time start_time = time.time() num = 0 for x in range(0, 10000000): # num += 2 * (x * x) num += 2 * x * x print("--- %s seconds ---" % (time.time() - start_time)) |
如果你
on the other is the opposite恩的手:在Java中,Java是
伊朗version of the program 10每个时代,这里是结果。P></
1 2 3 4 5 6 7 8 9 10 11 12 | 2 * x * x | 2 * (x * x) --------------------------------------- 1.7717654705047607 | 2.0789272785186768 1.735931396484375 | 2.1166207790374756 1.7093875408172607 | 2.024367570877075 1.7004504203796387 | 2.047525405883789 1.6676218509674072 | 2.254328966140747 1.699510097503662 | 2.0949244499206543 1.6889283657073975 | 2.0841963291168213 1.7243537902832031 | 2.1290600299835205 1.712965488433838 | 2.1942825317382812 1.7622807025909424 | 2.1200053691864014 |
首先,请注意我们在Python 2。x中没有看到相同的东西:
1 2 3 4 | >>> timeit("for i in range(1000): 2*i*i") 51.00784397125244 >>> timeit("for i in range(1000): 2*(i*i)") 50.48330092430115 |
所以这让我们相信这是由于python 3中整数的变化:具体来说,python3在任何地方都使用EDOCX1(任意大的整数)。
对于足够小的整数(包括我们在这里考虑的整数),cpython实际上只使用O(mn)年级逐位乘法算法(对于较大的整数,它切换到karatsuba算法)。你可以在源代码中看到这个。
这里有一个直接的方法可以看到这个(python 3):
1 2 3 4 | >>> timeit("a*b","a,b = 2, 123456**2", number=100000000) 5.796971936999967 >>> timeit("a*b","a,b = 2*123456, 123456", number=100000000) 4.3559221399999615 |
同样,将其与不到处使用任意长度整数的python 2进行比较:
1 2 3 4 | >>> timeit("a*b","a,b = 2, 123456**2", number=100000000) 3.0912468433380127 >>> timeit("a*b","a,b = 2*123456, 123456", number=100000000) 3.1120400428771973 |
(一个有趣的注意事项:如果你看一下源代码,你会发现算法实际上有一个特殊的平方数案例(我们在这里做的),但即使这样也不足以克服
整数的python intern表示是特殊的,它使用30位的槽:
1 2 3 4 5 | In [6]: sys.getsizeof(2**30-1) Out[6]: 28 # one slot + heading In [7]: sys.getsizeof(2**30) Out[7]: 32 # two slots |
所以,一切都发生在基本
对于想要计算2*4*4的人,有两种方法:
- (2*4)*4=8*4=32=30+2如果知道添加表,则立即添加。
- 2*(4*4)=2*16=2*10+2*6=(2*10+10)+2=30+2,因为我们必须停止操作。
Python也有同样的问题。如果
1 2 | (x*x)*2 => (a|b)*2 => (2*a|2*b) (2*x)*x => (2x)*x =>(2a|2b) |
在第一种情况下,EDCOX1×7操作是两次,而在第一种情况下只有一次。这就解释了差异。
如果您的基准测试是正确的(没有检查),可能是因为python整数可能是两种不同的东西:小的时候是本机整数(计算速度快),大的时候是大的整数(计算速度慢)。第一个语法在第一个操作之后保持较小的大小,而第二个语法可能导致两个涉及大整数的操作。
据我所知,在使用
1 2 3 4 5 6 7 8 9 | 7 28 LOAD_FAST 1 (num) 30 LOAD_CONST 3 (2) 32 LOAD_FAST 2 (x) 34 BINARY_MULTIPLY 36 LOAD_FAST 2 (x) 38 BINARY_MULTIPLY 40 INPLACE_ADD 42 STORE_FAST 1 (num) 44 JUMP_ABSOLUTE 24 |
1 2 3 4 5 6 7 8 9 | 7 28 LOAD_FAST 1 (num) 30 LOAD_CONST 3 (2) 32 LOAD_FAST 2 (x) 34 LOAD_FAST 2 (x) 36 BINARY_MULTIPLY <=== 1st multiply x*x in a temp value 38 BINARY_MULTIPLY <=== then multiply result with 2 40 INPLACE_ADD 42 STORE_FAST 1 (num) 44 JUMP_ABSOLUTE 24 |