快速傅里叶变换

多项式乘法

理解傅里叶变换首先要从多项式乘法开始。

快速傅里叶变换_第1张图片

多项式的系数表示和点值表示

多项式的系数表示

存在多项式

则称式(2)为多项式(1)的系数表示法,系数表示法下多项式乘法的算法复杂度为O(n2)。

 

多项式的点值表示

任意一个n阶多项式函数可由n+1个点来确定。

点值表示法下多项式乘法的算法复杂度为O(n)

系数表示转化为离散的点”称为离散傅里叶变换

离散的点”还原为”系数”表示法称为离散傅里叶反变换。

如何求一个多项式的点值表示?

带入n+1个x,分别求的f(x),求一次f(x)的时间复杂度为O(n),所以总的时间复杂度为O(n2).

利用复数的性质,可以简化计算。

复数

复数w满足wn=1,则称w是n次单位根。W的n次单位根有n个。

W的8次单位根和4次单位根。

快速傅里叶变换_第2张图片

复数的单位根存在如下性质:

复数使用结构体表示

typedef struct {
	double real;
	double img;
}complex;

FFT离散傅里叶变换

将系数表示法转化为点值表示法称为离散傅里叶变换,核心是需要找到n+1个点来表示n阶多项式函数。

多项式分解为奇偶次数项

快速傅里叶变换_第3张图片

快速傅里叶变换_第4张图片

快速傅里叶变换_第5张图片

至此,已经可以通过第一轮蝴蝶变换求得所有的f(x),且要带入的值减少了一半。

void initW(complex *W, int n)
{
	int i; 
	for (i = 0; i

 

也就是说,每一层对于一个确定的m,用对应的两个值可以更新出当前的值。这个操作称为蝴蝶变换

递归调用树

快速傅里叶变换_第6张图片

如果自底向上观察这颗树,将初始向量按照叶子的位置预先重排好的话,就可以实现自底向上一步步合并结果。

快速傅里叶变换_第7张图片

观察重排的规律,发现重排之后序列的下标为序列下标二进制数的翻转

void bit_reverse(int n, complex *x)
{
	complex t;
	for (int i = 0, j = 0; i != n; ++i)
	{
		if (i > j) {
			t = x[i];
			x[i] = x[j];
			x[j] = t;
		}
		for (int l = n >> 1; (j ^= l) < l; l >>= 1);
	}
}

 

在用代码实现的过程中,输入和输出都可以理解为长度为n的数组,n为2的p次方,不够的使用0补,所以需要将数据转化到复数域,FFT变换结束后再转换到实数域。

在用代码实现的过程中,输入和输出都可以理解为长度为n的数组,n为2的p次方,不够的使用0补,所以需要将数据转化到复数域,FFT变换结束后再转换到实数域。

void fft(float *input, unsigned int n)
{
	int i = 0, j = 0, k = 0, l = 0;
	complex up, down, product;
	complex *data = malloc(sizeof(complex) * n);

	for (j = 0; j < n; j++)
	{
		data[j].real = input[j];
		data[j].img = 0;
	}

	bit_reverse(n, data);

	for (i = 0; i< log(n) / log(2); i++)
	{
		l = 1 << i;
		for (j = 0; j

 

你可能感兴趣的:(Math)