求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)));
	}
}

歡迎指正!

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