赞
踩
在FFT算法中,我们假设输入序列的长度为 N N N,并且 N N N 是 2 2 2 的整数次幂,即 N = 2 n N=2^n N=2n,其中 n n n 是正整数。当输入序列中存在大量为零的元素时,会出现以下两种情况:
输入序列中的很多元素都是零,但是不是全部都是零。例如, N = 8 N=8 N=8,输入序列为 [ 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] [1,0,0,0,0,0,0,0] [1,0,0,0,0,0,0,0]。对这样一个例子进行FFT计算时,虽然输入序列中有很多零元素,但是计算的过程中还是需要对它们进行一定的计算,因为不对它们进行计算会影响计算的正确性。因此,在这种情况下,输入序列中存在零元素并不能够提高计算速度。
输入序列中的所有元素都是零。这时进行FFT计算时,由于计算公式中都需要对输入序列的各个元素进行加减乘除的计算,因此计算中涉及到的所有计算操作都会变成零,从而得到了所有元素都为零的输出序列。因此,这种情况下,输入序列中的零元素确实可以提高计算速度,因为它们让计算中的所有操作都变成了零。但这样的优化只在输入序列全是零的情况下才会产生效果,而在实际应用中,这种情况相当罕见。
因此,总体来说,在输入序列中存在大量零元素时,不能够保证FFT计算的速度会明显提高,而且可能还会使得计算的结果不正确。如果想要在计算FFT时获得更高的运算速度,可以使用一些优化技巧,例如使用快速傅里叶变换的变种算法(比如 Cooley-Tukey FFT算法、Bluestein’s FFT算法等),或者使用一些基于并行计算的算法来加速计算。
对于输入序列长度为 N N N 的FFT计算,它的运算复杂度可以看做是 O ( N log N ) O(N\log N) O(NlogN),其中 log N \log N logN是计算FFT的迭代次数。当输入序列中存在大量为零的元素时,我们可以通过以下两种方式来计算FFT的运算复杂度:
从输入序列的角度考虑。如果输入序列中的大多数元素都为零,我们可以用稀疏矩阵的概念来描述这个序列,即将这个序列视为一个矩阵中的一行,其中大部分元素都是零。在这种情况下,我们可以使用基于稀疏矩阵的FFT算法来计算FFT,这样可以将计算FFT的时间复杂度降到 O ( N log 2 N ) O(N\log^2 N) O(Nlog2N) 级别。但是需要注意,基于稀疏矩阵的FFT算法只对空间复杂度有要求,并不一定能够提高时间复杂度。
从FFT算法的角度考虑。如果输入序列中存在很多为零的元素,那么在计算FFT的过程中,有一些计算是可以优化的,因为一个数的乘积是零时,整个和式也一定是零。因此,我们可以在计算FFT时,特判输入序列中的零元素,将它们在计算过程中直接忽略掉,这样可以将计算FFT的时间复杂度降到 O ( N log M ) O(N\log M) O(NlogM) 级别,其中 M M M 是输入序列中非零元素的个数。但是需要注意,这种优化在实践中并不一定会提高计算速度。因为在实际应用中,输入序列中存在大量为零的元素的情况并不是很常见,而在处理稀疏数据时,往往需要用到一些专门的算法,比如 COO 格式、CSR 格式等,这些算法和FFT计算的时间复杂度没有相互关系。
在计算FFT的过程中,我们对输入序列进行了重排,将位置对应的元素分到了不同的组中进行计算。在计算过程中,如果一个位置对应的元素为零,那么在该位置所在的组中计算的加法和乘法都可以被直接忽略掉。因此,如果输入序列中有 M M M 个非零元素,那么在计算FFT时,我们只需要对这 M M M 个非零元素进行计算就可以了,其余的元素直接跳过即可。
设 N N N 为输入序列的长度, M M M 为非零元素的个数。在采用上述优化后,计算FFT的时间复杂度可以分为两个部分:
1.重排序列的时间复杂度为 O ( N ) O(N) O(N)。
2.计算FFT的时间复杂度为 O ( M log M ) O(M\log M) O(MlogM)。
因此,总的时间复杂度为 O ( N + M log M ) O(N+M\log M) O(N+MlogM),但是由于 M ≤ N M\leq N M≤N,因此该算法的时间复杂度可以简化为 O ( N log M ) O(N\log M) O(NlogM)。值得注意的是, M M M 的大小并不是常数,取决于输入序列中有多少个非零元素,因此这种优化算法的最差时间复杂度仍然为 O ( N log N ) O(N\log N) O(NlogN)。
这个简化的复杂度分析是有问题的,可能是存在一些混淆概念。具体来说, N N N 和 M M M 在这里应该指的是什么是不清楚的。以下是一种可能的分析方法。
假设输入序列的长度为 N N N,其中非零元素的个数为 M M M,且 M M M 是 N N N 的一个较小的常数倍。在这种情况下,如果我们采取特判输入序列中的零元素的策略,那么计算FFT的时间复杂度可以分为两个部分:
重排序列的时间复杂度为 O ( N ) O(N) O(N)。
计算FFT的时间复杂度为 O ( M log M ) O(M\log M) O(MlogM)。
因此,总的时间复杂度为 O ( N + M log M ) O(N+M\log M) O(N+MlogM)。
不过需要注意的是, N N N 和 M M M 都在考虑中,因此将其简化成 O ( N log M ) O(N\log M) O(NlogM) 是不严谨的。而且即便存在 M = O ( 1 ) M = O(1) M=O(1) 的情况,此时算法的时间复杂度还是 O ( N ) O(N) O(N),因为重排序的时间复杂度仍然与输入序列长度成线性关系。
因此,是否能够将 O ( N + M log M ) O(N+M\log M) O(N+MlogM) 的复杂度简化为 O ( N log M ) O(N\log M) O(NlogM),取决于我们定义 N N N 和 M M M 的具体含义。如果 M M M 只表示输入序列中非零元素的个数,那么 N N N 和 M M M 的比例可能非常大,这种简化是不合适的。但是如果 M M M 是 N N N 的一个较小的常数倍,那么 O ( N + M log M ) O(N+M\log M) O(N+MlogM) 的复杂度确实可以用 O ( N log M ) O(N\log M) O(NlogM) 来简化。
假设输入序列的长度为 N N N,其中非零元素的个数为 M M M。在大部分信号点为零的情况下,FFT计算的时间复杂度可以优化为 O ( N log M ) O(N\log M) O(NlogM)。下面分别列出复数乘法的运算次数和复数加法的运算次数:
复数乘法运算次数:
每个迭代步骤需要进行
N
/
2
N/2
N/2 次复数乘法运算,一共有
log
2
N
\log_2 N
log2N 个迭代步骤。即总复杂度为
O
(
N
log
N
)
O(N\log N)
O(NlogN) 的FFT算法需要进行
N
log
N
N\log N
NlogN 次复数乘法运算。在大部分信号点为零的情况下,所需计算的非零乘积个数为
M
log
2
M
M\log_2 M
Mlog2M,因此,采用特判输入序列中的零元素的优化方法后,FFT算法的总复数乘法运算次数为
O
(
M
log
M
)
O(M\log M)
O(MlogM)。
复数加法运算次数:
每个迭代步骤需要进行
N
/
2
N/2
N/2 次复数加法运算,一共有
log
2
N
\log_2 N
log2N 个迭代步骤。因此,总复杂度为
O
(
N
log
N
)
O(N\log N)
O(NlogN) 的FFT算法需要进行
N
log
N
N\log N
NlogN 次复数加法运算。在大部分信号点为零的情况下,输入序列中非零元素的个数为
M
M
M,则采用特判输入序列中的零元素的优化方法后,FFT算法的总复数加法运算次数最多为
2
M
log
2
M
2M\log_2 M
2Mlog2M,因为一次加法有可能被用了两次。
需要注意的是,这里计算的复杂度只考虑了复数乘法和复数加法的运算次数,并没有考虑其他基本运算(例如减法、除法等)和存储开销等。因此,这个计算复杂度的方法只是一种简化的方法,具体情况还需要根据具体算法和实现进行分析。
您的推导是正确的。在输入序列中非零元素的位置不同时,复数乘法和复数加法的次数是不一致的,因此不能用 O ( M log M ) O(M\log M) O(MlogM) 统一代表它们的运算次数。
在一般情况下,如果要分别计算复数乘法和复数加法的运算次数,需要考虑每个位置对应的元素在FFT计算过程中的实际参与次数。对于某个非零元素,其实际参与次数取决于它所处于什么位置以及在什么迭代步骤中被计算。
在实际应用中,这种复杂度的计算较为困难,而且往往也没有必要进行如此细致的复杂度分析。采用特判输入序列中的零元素的优化算法能够有效减少部分复杂度,并且在实际应用中已经得到了广泛的应用。
假设在FFT计算过程中,输入序列中非零元素的个数依次为 M 1 , M 2 , … , M N M_1, M_2, \ldots, M_N M1,M2,…,MN,其中 M 1 = 1 M_1=1 M1=1, M N = M M_N=M MN=M, M M M表示输入序列中非零元素的总个数。并且假设每个非零元素都参与了所有迭代步骤的计算。
在这种情况下,FFT的计算复杂度为 O ( N M log M ) O(NM\log M) O(NMlogM),其中 M log M M\log M MlogM 表示计算 M M M 个非零元素的FFT的复杂度, N M NM NM 表示总共需要迭代 N N N 次,每次迭代中非零元素的个数为 M i M_i Mi,需要进行 M i M_i Mi 次复杂度为 O ( log M i ) O(\log M_i) O(logMi) 的FFT计算。
复数乘法的运算次数可以用相同的方式计算出来。在计算 M i M_i Mi 个非零元素的FFT过程中,每个非零元素都需要参与 N N N 次复数乘法的计算,因此总复数乘法运算次数为 O ( N M log M ) O(NM\log M) O(NMlogM)。
复数加法的运算次数与复数乘法的运算次数类似,也可以用相同的方式计算出来。在计算 M i M_i Mi 个非零元素的FFT过程中,每个非零元素都需要参与 N N N 次复数加法的计算,因此总复数加法运算次数也为 O ( N M log M ) O(NM\log M) O(NMlogM)。
需要注意的是,由于每个非零元素不一定在所有位置都参与计算,因此实际的复杂度可能低于 O ( N M log M ) O(NM\log M) O(NMlogM)。如果存在一些特殊的输入序列,其非零元素的位置和值的分布比较规则,那么可能会出现一些优化算法,可以进一步降低FFT计算的复杂度。
假设在FFT计算过程中,输入序列中非零元素的个数依次为 M 1 , M 2 , … , M N M_1, M_2, \ldots, M_N M1,M2,…,MN,其中 M 1 = 1 M_1=1 M1=1, M N = N M_N=N MN=N。并且假设每个非零元素都参与了所有迭代步骤的计算。
在这种情况下,FFT的计算复杂度为 O ( N 2 log N ) O(N^2\log N) O(N2logN),其中 N 2 N^2 N2 表示总共需要迭代 N N N 次,每次迭代中非零元素的个数为 M i = i M_i=i Mi=i,需要进行 i i i 次复杂度为 O ( log i ) O(\log i) O(logi) 的FFT计算。另外,由于 N N N 个非零元素都在最终的结果中参与计算,因此最后还需要进行一次 N N N 个元素的FFT计算。
复数乘法的运算次数可以用相同的方式计算出来。在计算 M i = i M_i=i Mi=i 个非零元素的FFT过程中,每个非零元素都需要参与 N N N 次复数乘法的计算,因此总复数乘法运算次数为 O ( N 2 log N ) O(N^2\log N) O(N2logN)。
复数加法的运算次数与复数乘法的运算次数类似,也可以用相同的方式计算出来。在计算 M i = i M_i=i Mi=i 个非零元素的FFT过程中,每个非零元素都需要参与 N N N 次复数加法的计算,因此总复数加法运算次数也为 O ( N 2 log N ) O(N^2\log N) O(N2logN)。
需要注意的是,输入序列中非零元素的个数和位置不同,会对FFT运算的复杂度产生重要的影响。在某些特殊情况下,可能存在一些优化算法,可以进一步降低FFT计算的复杂度。
您的求和式子是正确的,它表示FFT算法总的计算复杂度。但是根据 O O O符号定义的惯例,我们通常省略常数因子和低阶项,只考虑高阶项。这是因为,在实际问题中,常数和低阶项在问题规模足够大的时候往往变得微不足道,因此对算法的实际效率影响不大。因此,FFT算法的总的计算复杂度通常表示为 O ( N log N ) O(N\log N) O(NlogN)。
另外,您的求和式子可进一步转化为 ∑ i = 1 N i log i = N log N + O ( N ) \sum_{i=1}^N i\log i=N\log N + O(N) ∑i=1Nilogi=NlogN+O(N),其中 O ( N ) O(N) O(N)可以忽略不计。因此,FFT算法的总的计算复杂度不仅是 O ( N log N ) O(N\log N) O(NlogN),而且系数是 N N N,也就是说,比起一般情况下的 O ( N log N ) O(N\log N) O(NlogN),FFT算法的系数较小,实际上是一个非常高效的算法。
∑ i = 1 N i log i \sum_{i=1}^N i\log i ∑i=1Nilogi 的求和结果是 N log N − N + O ( log N ) N\log N - N + O(\log N) NlogN−N+O(logN)。这个结论可以通过分部求和和斯特林公式得到。
首先,我们可以对 ∑ i = 1 N i log i \sum_{i=1}^N i\log i ∑i=1Nilogi 进行分部求和,得到:
∑
i
=
1
N
i
log
i
=
∑
i
=
1
N
log
i
⋅
∑
j
=
1
i
j
=
∑
i
=
1
N
log
i
⋅
i
(
i
+
1
)
2
=
1
2
∑
i
=
1
N
(
i
2
+
i
)
log
i
=
1
2
(
∑
i
=
1
N
i
2
log
i
+
∑
i
=
1
N
i
log
i
)
N∑i=1ilogi=N∑i=1logi⋅i∑j=1j=N∑i=1logi⋅i(i+1)2=12N∑i=1(i2+i)logi=12(N∑i=1i2logi+N∑i=1ilogi)
接下来,我们可以使用斯特林公式 n ! ≈ 2 π n ⋅ ( n / e ) n n! \approx \sqrt{2\pi n} \cdot (n/e)^n n!≈2πn ⋅(n/e)n,将 log n ! \log n! logn! 近似为 1 2 log 2 π n + n log n − n + O ( log n ) \frac{1}{2}\log 2\pi n + n\log n - n + O(\log n) 21log2πn+nlogn−n+O(logn),进而计算 ∑ i = 1 N i log i \sum_{i=1}^N i\log i ∑i=1Nilogi。具体如下:
∑
i
=
1
N
i
2
log
i
=
∑
i
=
1
N
log
(
i
i
2
)
=
log
∏
i
=
1
N
i
i
2
=
log
(
∏
i
=
1
N
i
i
)
2
=
2
log
N
!
≈
2
(
1
2
log
(
2
π
N
)
+
N
log
N
−
N
+
O
(
log
N
)
)
=
N
log
N
+
O
(
N
log
N
)
N∑i=1i2logi=N∑i=1log(ii2)=logN∏i=1ii2=log(N∏i=1ii)2=2logN!≈2(12log(2πN)+NlogN−N+O(logN))=NlogN+O(NlogN)
∑
i
=
1
N
i
log
i
=
∑
i
=
1
N
log
i
i
=
log
∏
i
=
1
N
i
i
=
log
N
!
2
≈
2
(
1
2
log
(
2
π
N
)
+
N
log
N
−
N
+
O
(
log
N
)
)
=
N
log
N
−
N
+
O
(
log
N
)
N∑i=1ilogi=N∑i=1logii=logN∏i=1ii=logN!2≈2(12log(2πN)+NlogN−N+O(logN))=NlogN−N+O(logN)
因此, ∑ i = 1 N i log i = 1 2 ( ∑ i = 1 N i 2 log i + ∑ i = 1 N i log i ) = N log N − N + O ( log N ) \sum_{i=1}^N i\log i = \frac{1}{2}(\sum_{i=1}^N i^2\log i + \sum_{i=1}^N i\log i) = N\log N - N + O(\log N) ∑i=1Nilogi=21(∑i=1Ni2logi+∑i=1Nilogi)=NlogN−N+O(logN)。
考虑
(
∏
i
=
1
N
i
i
)
\left(\prod_{i=1}^N i^i\right)
(∏i=1Nii) 中的每一项作为一个因子:
(
∏
i
=
1
N
i
i
)
=
1
1
⋅
2
2
⋅
3
3
⋅
⋯
⋅
N
N
\left(\prod_{i=1}^N i^i\right)=1^1 \cdot 2^2 \cdot 3^3 \cdot \cdots \cdot N^N
(i=1∏Nii)=11⋅22⋅33⋅⋯⋅NN
根据数学中乘法的结合律和交换律,上式中的因子可以改写为:
(
∏
i
=
1
N
i
i
)
=
1
⋅
2
2
⋅
3
3
⋅
⋯
⋅
(
N
−
1
)
N
−
1
⋅
N
N
\left(\prod_{i=1}^N i^i\right)=1 \cdot 2^2 \cdot 3^3 \cdot \cdots \cdot (N-1)^{N-1}\cdot N^N
(i=1∏Nii)=1⋅22⋅33⋅⋯⋅(N−1)N−1⋅NN
接下来,我们考虑 ( N − 1 ) N − 1 (N-1)^{N-1} (N−1)N−1 这个因子。根据指数运算法则, ( N − 1 ) N − 1 = ( ( N − 1 ) ! ) N − 1 (N-1)^{N-1}=((N-1)!)^{N-1} (N−1)N−1=((N−1)!)N−1. 再次利用乘法的交换律,将 ( N − 1 ) N − 1 (N-1)^{N-1} (N−1)N−1 和 N N N^N NN 放在一起:
(
∏
i
=
1
N
i
i
)
=
1
⋅
2
2
⋅
3
3
⋅
⋯
⋅
(
(
N
−
2
)
!
N
−
2
⋅
(
N
−
1
)
N
−
1
)
⋅
N
N
=
(
N
!
)
2
=
N
!
⋅
N
!
(N∏i=1ii)=1⋅22⋅33⋅⋯⋅((N−2)!N−2⋅(N−1)N−1)⋅NN=(N!)2=N!⋅N!
因此, ( ∏ i = 1 N i i ) = N ! \left(\prod_{i=1}^N i^i\right)=N! (∏i=1Nii)=N!。
非常抱歉,我的回答有误。 ( N − 1 ) N − 1 (N-1)^{N-1} (N−1)N−1 并不等于 ( ( N − 1 ) ! ) N − 1 ((N-1)!)^{N-1} ((N−1)!)N−1。感谢您的纠正。
下面给出一个正确的证明:
∏
i
=
1
N
i
i
=
1
1
⋅
2
2
⋅
3
3
⋅
⋯
⋅
(
N
−
1
)
N
−
1
⋅
N
N
=
(
1
⋅
2
⋅
3
⋯
N
)
(
1
+
2
+
⋯
+
N
)
(
1
!
⋅
2
!
⋅
3
!
⋯
N
!
)
N
−
1
⋅
N
N
=
N
!
N
−
1
⋅
N
N
(
1
!
⋅
2
!
⋅
3
!
⋯
N
!
)
N
−
1
=
(
N
!
)
N
N
!
(
N
−
1
)
!
⋯
2
!
1
!
=
N
!
N∏i=1ii=11⋅22⋅33⋅⋯⋅(N−1)N−1⋅NN=(1⋅2⋅3⋯N)(1+2+⋯+N)(1!⋅2!⋅3!⋯N!)N−1⋅NN=N!N−1⋅NN(1!⋅2!⋅3!⋯N!)N−1=(N!)NN!(N−1)!⋯2!1!=N!
因此, ∏ i = 1 N i i = N ! \prod_{i=1}^N i^i = N! ∏i=1Nii=N!。注意,上述证明利用了乘法的交换律和结合律,以及 ∑ i = 1 N i = 1 2 N ( N + 1 ) \sum_{i=1}^N i = \frac{1}{2}N(N+1) ∑i=1Ni=21N(N+1) 和 ∑ i = 1 N i 2 = 1 6 N ( N + 1 ) ( 2 N + 1 ) \sum_{i=1}^N i^2 = \frac{1}{6}N(N+1)(2N+1) ∑i=1Ni2=61N(N+1)(2N+1)。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。