好吧,我希望标题有点意义。我做了一个快速傅立叶变换的代码,想看看如何能更快。所以这里是代码('code1'),我按照FFT的要求进行交换。
stp='''
import numpy as nn
D=2**18
N=12
w=(nn.linspace(0,D-1,D)%2**N<(2**N/2))-.5 #square wave
f=w[0:2**N]+nn.zeros(2**N)*1j #it takes only one wavelength from w
'''
code1='''
for m in range(N):
for l in range(2**m):
for k in range(2**(N-1-m)):
t=f[k+l*2**(N-m)]
f[k+l*2**(N-m)]=(t+f[k+l*2**(N-m)+2**(N-1-m)])
f[k+l*2**(N-m)+2**(N-1-m)]=(t-f[k+l*2**(N-m)+2**(N-1-m)])*nn.e**(-2*nn.pi*1j*k*2**(m)/2**N)
'''
print(timeit.timeit(setup=stp,stmt=code1,number=1))
我引入了一个新的变量't'. 这样输出的时间是0.132。
所以我想如果我这样做,应该会更快(设置和以前一样)。
code2='''
for m in range(N):
for l in range(2**m):
for k in range(2**(N-1-m)):
f[k+l*2**(N-m)],f[k+l*2**(N-m)+2**(N-1-m)]=f[k+l*2**(N-m)]+f[k+l*2**(N-m)+2**(N-1-m)],(f[k+l*2**(N-m)]-f[k+l*2**(N-m)+2**(N-1-m)])*nn.e**(-2*nn.pi*1j*k*2**(m)/2**N)
'''
print(timeit.timeit(setup=stp,stmt=code2,number=1))
因为现在我做的是两个作业,而不是三个(这是我的想法)。但看起来这样做其实更慢(0.152)。有人知道为什么吗?有谁知道有什么方法可以使这种交换比之前的 t=a,a=f(a,b),b=g(t,b)
我之前介绍过,因为我很难相信这是最有效的方法。
EDIT:添加了实际代码,而不是伪代码。
更多EDIT:我试着在不使用Numpy的情况下运行同样的东西。两者都更快,所以这是积极的,但同样是 t=a,a=f(a,b),b=g(t,b)
的方法似乎要快一些(0.104)。a,b=f(a,b),g(a,b)
法(0.114)。所以,谜底依然存在。
新代码。
stpsansnumpy='''
import cmath as mm
D=2**18
N=12
w=[0]*D
for i in range(D):
w[i]=(i%2**N<(2**N/2))-.5 #square wave
f=w[0:2**N]+[0*1j]*2**N #it takes only one wavelength from w
'''
code1math='''
for m in range(N):
for l in range(2**m):
for k in range(2**(N-1-m)):
t=f[k+l*2**(N-m)]
f[k+l*2**(N-m)]=(t+f[k+l*2**(N-m)+2**(N-1-m)])
f[k+l*2**(N-m)+2**(N-1-m)]=(t-f[k+l*2**(N-m)+2**(N-1-m)])*mm.exp(-2*mm.pi*1j*k*2**(m)/2**N)
'''
print(timeit.timeit(setup=stpsansnumpy,stmt=code1math,number=1))
and:
code2math='''
for m in range(N):
for l in range(2**m):
for k in range(2**(N-1-m)):
f[k+l*2**(N-m)],f[k+l*2**(N-m)+2**(N-1-m)]=f[k+l*2**(N-m)]+f[k+l*2**(N-m)+2**(N-1-m)],(f[k+l*2**(N-m)]-f[k+l*2**(N-m)+2**(N-1-m)])*mm.exp(-2*mm.pi*1j*k*2**(m)/2**N)
'''
print(timeit.timeit(setup=stpsansnumpy,stmt=code2math,number=1))
在第一个版本中,我看到5个索引操作,而在第二个版本中,我看到6个。我并不奇怪,6个索引操作(包括你在其中使用的所有计算)比5个更贵。
与你在这些代码片段中所做的所有计算相比,创建一个临时变量,或者创建一个临时元组,都是小菜一碟。
如果你能分享一下为什么你认为其中一个比另一个慢,以及你的代码是否会像Python代码那样被正确格式化,那就更好了。
类似这样。
from timeit import timeit
def f(a, b):
return a
def g(a, b):
return a
def extra_var(a, b):
t = a
a = f(a, b)
b = g(t, b)
return a, b
def swap_direct(a, b):
a, b = f(a, b), g(a, b)
return a, b
print(timeit(lambda: extra_var(1, 2)))
print(timeit(lambda: swap_direct(1, 2)))
然而,如果你分享了,你可能会发现和我一样的结果。
0.2162299
0.21171479999999998
结果是如此的接近,以至于在连续的运行中,任何一个函数都会显得快一点或者慢一点。
所以,你会增加体积。
print(timeit(lambda: extra_var(1, 2), number=10000000))
print(timeit(lambda: swap_direct(1, 2), number=10000000))
神秘感就会消失
2.1527828999999996
2.1225841
直接交换实际上是稍微快了一点,就像预期的那样. 你刚才的做法有什么不同,给你带来了其他的结果?
你说,当你在更复杂的代码上下文中实现它时,你看到了差异--然而,这表明很可能你的代码本身就是可能的罪魁祸首,这就是为什么StackOverflow建议你分享一个最小的、可复制的例子,这样人们就可以真正尝试你说的发生的事情,而不是不得不相信你的话。
在大多数情况下,事实证明有人犯了一个错误,一切都在预期之中。在某些情况下,你会得到一个有趣的答案。