给定一组n个粒子,在平面上的点(1,0),(2,0),......(n,0)上发现电荷载流子。 在点(i,0)中发现的粒子电荷记为Qi。作用于粒子的力由公式给出:
C是库仑常数。
为总复杂度为O(nlgn)的所有粒子提供算法来计算Fi。 提示:使用FFT算法。
似乎Fi已经分为偶数和奇数点。
我想把每个和除以计算FFT(但除以什么......?)和 然后总和一半的点(因为这是FFT的原因),然后减去公式上给出的总和的结果..
有关如何做得更好的任何想法?
答案 0 :(得分:1)
看起来像是作业,所以没有为你的案例提供实际的代码而是一些例子和提示 对于 FFT 类算法:
通过零填充将数据集大小设置为2
的幂
所以划分为一半很简单(没有剩余部分)
创建递归函数来计算类似FFT的东西
在其中重新排序数据集,将其分成两半并递归调用它自己2次(每次使用不同的一半数据)并添加if语句以启动。如果数据集size<=1
或2
然后直接返回计算值以确保递归停止。
在这两次递归调用之后,重新排序数据并将它们组合到结果
根据需要从结果中删除零填充
例如,这是我的 NTT 的样子(数论变换)
//---------------------------------------------------------------------------
void fourier_NTT:: NTT_fast(DWORD *dst,DWORD *src,DWORD n,DWORD w)
{
// recursion stop condition if the data is single number ...
if (n<=1) { if (n==1) dst[0]=src[0]; return; }
DWORD i,j,a0,a1,n2=n>>1,w2=modmul(w,w);
// reorder even,odd to dst array
for (i=0,j=0;i<n2;i++,j+=2) dst[i]=src[j];
for ( j=1;i<n ;i++,j+=2) dst[i]=src[j];
// recursion
NTT_fast(src ,dst ,n2,w2); // even
NTT_fast(src+n2,dst+n2,n2,w2); // odd
// restore results
for (w2=1,i=0,j=n2;i<n2;i++,j++,w2=modmul(w2,w))
{
a0=src[i];
a1=modmul(src[j],w2);
dst[i]=modadd(a0,a1);
dst[j]=modsub(a0,a1);
}
}
//---------------------------------------------------------------------------
完整的源代码和更多信息是here。
始终将快速实施结果与缓慢实施进行比较!!!
某些系数或索引中的小错误可能会导致数据集大小不断增加的结果存在巨大差异。
对于 NTT 以上功能,这是一个缓慢的实现:
//---------------------------------------------------------------------------
void fourier_NTT:: NTT_slow(DWORD *dst,DWORD *src,DWORD n,DWORD w)
{
DWORD i,j,wj,wi,a,n2=n>>1;
for (wj=1,j=0;j<n;j++)
{
a=0;
for (wi=1,i=0;i<n;i++)
{
a=modadd(a,modmul(wi,src[i]));
wi=modmul(wi,wj);
}
dst[j]=a;
wj=modmul(wj,w);
}
}
//---------------------------------------------------------------------------
<强> [注释] 强>
现在你有了分离方程式
导出直接计算的值与2x半递归调用计算的值之间的系数差异,并相应地恢复结果,以使输出与正确的结果匹配。