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


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

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

    Xleft ( j 
ight )=sum_{k=0}^{N-1}Aleft ( k 
ight )W^{jk}left ( 0leq jleq N-1 
ight )

    Aleft ( j 
ight )=frac{1}{N}sum_{k=0}^{N-1}Xleft ( k 
ight )W^{-jk},left ( 0leq jleq N-1 
ight )

    具体算法和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("
    Source初始化:
    ");
    	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("
    ");
    	}
    	printf("
    Result初始化:
    ");
    	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("
    ");
    	}
    	printf("
    Root初始化:
    ");
    	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("
    ");
    	}
    
    	//对结果取平均数,average=1/N,复数乘以常数在一开始定义
    	for (i = 0; i < N; i++)
    	{
    		Result[i] =mult1( IFFT(Source, N, Root[i], Result[i]) , average );
    	}
    
    	//结果表示
    	printf("
    Result计算结果:
    ");
    	for (i = 0; i < N; i++)
    	{
    		printf("%.4f ", Result[i].real);
    		printf("+%.4fj  ", Result[i].imag);
    		printf("
    ");
    	}
    
    	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)));
    	}
    }
    

    欢迎指正!

  • 相关阅读:
    [c++]在类中定义常量的几个做法
    VC6中使用高版本系统API的方法
    Delphi编程中实现窗口分割
    Win32 SDK窗口程序代码(含详细注释)
    [c++]在C++中定义常量的两种方法的比较
    VC6里的_WIN32_WINNT宏
    [VC]自己实现TRACE功能
    [delphi]保证程序只运行一个实例
    转载:C# 设置文件夹权限(代码简单)
    VC:动态链接库
  • 原文地址:https://www.cnblogs.com/cg-bestwishes/p/10681151.html
Copyright © 2020-2023  润新知