求Q(x)模X^n + 1的余数多项式的FFT的逆变换IFFT

本文的IFFT算法是在FFT基础上改变的,之前的FFT算法链接:https://blog.csdn.net/great978/article/details/84033080

这里给出离散傅里叶变换以及逆变换的公式:

X\left ( j \right )=\sum_{k=0}^{N-1}A\left ( k \right )W^{jk}\left ( 0\leq j\leq N-1 \right )

A\left ( j \right )=\frac{1}{N}\sum_{k=0}^{N-1}X\left ( k \right )W^{-jk},\left ( 0\leq j\leq N-1 \right )

具体算法和FFT几乎一致,同样是分开奇偶项,一直到最后两项,然后递归求和,以加法运算代替乘幂运算,和FFT算法不同在于

  1. 最后的复数需要求一个1/N,这需要我们额外定义一个复数乘以常数的乘法方法;
  2. 对于根值root,这里面需要求一个共轭(即倒数)

下面给出具体C语言代码:

// IFFT.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#define _CRT_SECURE_NO_WARNINGS
#include "stdlib.h"
#include "math.h"
#include "stdio.h"


#define K 3

#define Pi  3.1415927   //定义圆周率Pi
#define LEN sizeof(struct Compx)  //定义复数结构体大小

//-----定义复数结构体-----------------------
struct Compx
{
	double real;
	double imag;
}Compx;

//-----复数乘法运算函数---------------------
struct Compx mult(struct Compx b1, struct Compx b2)
{
	struct Compx b3;
	b3.real = b1.real*b2.real - b1.imag*b2.imag;
	b3.imag = b1.real*b2.imag + b1.imag*b2.real;
	return(b3);
}

struct Compx mult1(struct Compx p, double q)
{
	struct Compx r;
	r.real = p.real*q;
	r.imag = p.imag*q;
	return(r);
}

//-----复数加法运算函数---------------------
struct Compx add(struct Compx a, struct Compx b)
{
	struct Compx c;
	c.real = a.real + b.real;
	c.imag = a.imag + b.imag;
	return(c);
}

struct Compx IFFT(struct Compx *t, int n, struct Compx root, struct Compx result);

int main()
{
	int N, i;
	N = 8;
	double average = 1 / (double)N;

	int x[8];
	for (i = 0; i < N; i++)
	{
		scanf("%d", &x[i]);
	}

	struct  Compx * Source = (struct Compx *)malloc(N*LEN);			//为结构体分配存储空间
	struct  Compx * Result = (struct Compx *)malloc(N*LEN);
	struct  Compx * Root = (struct Compx *)malloc(N*LEN);


	//初始化======================================= 
	printf("\nSource初始化:\n");
	for (i = 0; i < N; i++)
	{
		Source[i].real = x[i];
		Source[i].imag = 0;
		printf("%.4f ", Source[i].real);
		printf("+%.4fj  ", Source[i].imag);
		printf("\n");
	}
	printf("\nResult初始化:\n");
	for (i = 0; i < N; i++)
	{
		Result[i].real = 0;
		Result[i].imag = 0;
		printf("%.4f ", Result[i].real);
		printf("+%.4fj  ", Result[i].imag);
		printf("\n");
	}
	printf("\nRoot初始化:\n");
	for (i = 0; i < N; i++)
	{
		Root[i].real = cos(2 * Pi * (2 * i + 1) / (2 * N));

		//在IFFT中,需要对根值取共轭,即cos值不变,sin取反
		Root[i].imag = -sin(2 * Pi * (2 * i + 1) / (2 * N));
		printf("%.4f ", Root[i].real);
		printf("+%.4fj  ", Root[i].imag);
		printf("\n");
	}

	//对结果取平均数,average=1/N,复数乘以常数在一开始定义
	for (i = 0; i < N; i++)
	{
		Result[i] =mult1( IFFT(Source, N, Root[i], Result[i]) , average );
	}

	//结果表示
	printf("\nResult计算结果:\n");
	for (i = 0; i < N; i++)
	{
		printf("%.4f ", Result[i].real);
		printf("+%.4fj  ", Result[i].imag);
		printf("\n");
	}

	return 0;
}

struct Compx IFFT(struct Compx *t, int n, struct Compx root, struct Compx result)
{
	int i, j;
	struct  Compx * even = (struct Compx *)malloc((n / 2) * LEN);
	struct  Compx * odd = (struct Compx *)malloc((n / 2) * LEN);

	//划分奇偶项 
	for (i = 0, j = 0; i < n; i += 2, j++)
	{
		even[j].real = t[i].real;
		even[j].imag = t[i].imag;
	}
	for (i = 1, j = 0; i < n; i += 2, j++)
	{
		odd[j].real = t[i].real;
		odd[j].imag = t[i].imag;
	}

	if (n == 2)
	{
		struct Compx s = add(even[0], mult(root, odd[0]));
		return add(result, s);
	}
	else
	{
		return add(IFFT(even, n / 2, mult(root, root), result), mult(root, IFFT(odd, n / 2, mult(root, root), result)));
	}
}

欢迎指正!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章