众所周知,将乘法、整数除法和模运算重写为位运算可以更高效地完成:
>>> x = randint(50000, 100000)
>>> x << 2 == x * 4
True
>>> x >> 2 == x // 4
True
>>> x & 3 == x % 4
True
在编译语言中,例如C/C++和Java,测试表明位运算通常比算术运算更快。 (请参见此处和此处)。然而,当我在Python中进行这些测试时,得到了相反的结果:
In [1]: from random import randint
...: nums = [randint(0, 1000000) for _ in range(100000)]
In [2]: %timeit [i * 8 for i in nums]
7.73 ms ± 397 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [3]: %timeit [i << 3 for i in nums]
8.22 ms ± 368 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [4]: %timeit [i // 8 for i in nums]
7.05 ms ± 393 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [5]: %timeit [i >> 3 for i in nums]
7.55 ms ± 367 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [6]: %timeit [i % 8 for i in nums]
5.96 ms ± 503 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [7]: %timeit [i & 7 for i in nums]
8.29 ms ± 816 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
正如您所看到的,位运算比其算术运算相对较慢,特别是模数运算。我针对另一组数字重复进行了此项测试,并得到了相同的结果。这是有原因的吗?这些测试是在CPython 3.6.7中进行的,如果这很重要。
int
对象与C语言中的int
完全不同,它们是对象。底层表示甚至不是一个Cint
类型,而是由数字数组组成的,如果你懂C语言,可以自己看一下:https://github.com/python/cpython/blob/master/Include/longintrepr.h 这是因为Python的int
对象是任意大小的,而不是固定大小的。 - juanpa.arrivillagai % < 2的幂>
是否在进行位移操作。据我所知,它并没有在进行位移操作,但是也许优化更深入,所以“dis”模块无法揭示它......我不确定。 - iz_x & (x-1) == 0
是否为2的幂,然后使用类似于POSIXffs()
或 x86bsf
/tzcnt
的位扫描来获取移位计数可能并不值得,除非实现预计2的幂非常普遍。(仅在除法时使用,如果输入具有多个limb,则不要使用乘法) - Peter Cordes