我写了一个简单的Eratosthenes筛子,它使用一个列表并将它们变成零,如果不是素数,就像这样:
sed 's/\([0-9][0-9]*\)\.\([0-9][0-9]*\)/\1,\2/'
我用def eSieve(n): #Where m is fixed-length list of all integers up to n
'''Creates a list of primes less than or equal to n'''
m = [1]*(n+1)
for i in xrange(2,int((n)**0.5)+1):
if m[i]:
for j in xrange(i*i,n+1,i):
m[j]=0
return [i for i in xrange(2,n) if m[i]]
测试了它运行的速度并得到了:
%timeit
我认为,如果我将#n: t
#10**1: 7 μs
#10**2: 26.6 μs
#10**3: 234 μs
#10**4: 2.46 ms
#10**5: 26.4 ms
#10**6: 292 ms
#10**7: 3.27 s
和[1]
更改为布尔值,它会更快地运行......但它却恰恰相反:
0
为什么布尔变慢?
答案 0 :(得分:13)
这是因为True
和False
在Python 2中被查找为全局变量。0
和1
文字只是常量,由快速数组引用查找,而globals是全局命名空间中的字典查找(落入内置命名空间):
>>> import dis
>>> def foo():
... a = True
... b = 1
...
>>> dis.dis(foo)
2 0 LOAD_GLOBAL 0 (True)
3 STORE_FAST 0 (a)
3 6 LOAD_CONST 1 (1)
9 STORE_FAST 1 (b)
12 LOAD_CONST 0 (None)
15 RETURN_VALUE
使用True
字节码查找LOAD_GLOBAL
值,而使用1
将LOAD_CONST
文字值复制到堆栈。
如果你制作True
和False
当地人,你可以再次提高它们的速度:
def eSieve(n, True=True, False=False):
m = [True]*(n+1)
for i in xrange(2,int((n)**0.5)+1):
if m[i]:
for j in xrange(i*i,n+1,i):
m[j]=False
return [i for i in xrange(2,n) if m[i]]
将True
和False
作为参数的默认值赋予函数,将这些名称作为locals,具有完全相同的值;再次使用简化版本:
>>> def bar(True=True, False=False):
... True == False
...
>>> dis.dis(bar)
2 0 LOAD_FAST 0 (True)
3 LOAD_FAST 1 (False)
6 COMPARE_OP 2 (==)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
注意LOAD_FAST
操作码,现在索引就像LOAD_CONST
字节码一样; CPython函数中的locals存储在数组中,就像字节码常量一样。
随着这种变化,使用布尔胜利,尽管只是一小部分;我的时间:
# n integers globals locals
# 10**1 4.31 µs 4.2 µs 4.2 µs
# 10**2 17.1 µs 17.3 µs 16.5 µs
# 10**3 147 µs 158 µs 144 µs
# 10**4 1.5 ms 1.66 ms 1.48 ms
# 10**5 16.4 ms 18.2 ms 15.9 ms
# 10**6 190 ms 215 ms 189 ms
# 10**7 2.21 s 2.47 s 2.18 s
差别并非如此之大,因为Python布尔只是一个int
子类。
请注意,在Python 3中,True
和False
已成为关键字,无法再分配给它们,因此可以将它们视为整数文字。