我們一般意義上學習的FFT都是基於的,即FFT中的單位根我們取的是,但是在某些情況下我們需要上的FFT和IFFT變換。
1、直接想到的思路是把的根替換成的根。
解法:的根可以使用的2n個根中的奇數次根得到,即,但是這種做法在FFT運算中可行,在IFFT逆運算下則不可行,我們一般的IFFT運算時把替換成,並且最後除以一個n得到IFFT運算的結果。如下
但是我們需要在上做IFFT變換的時候不能簡單的把根替換成,因爲根據FFT的點值多項式的形式,只有根是的形式的時候,纔可以使用
因爲根是 的形式的時候,
在上IFFT求逆的時候,不成立,直接替換根的做法是不可行的。
2、新的做法,擴展到2n次
設 ,,,f(x)是n次多項式。
令:
則有:
FFT計算步驟:
(1)計算
(2)此時F(x)是m次方的,計算F(x)在上的FFT(就是以前一般形式的FFT)
(3)輸出F(x) 的FFT變換之後的奇數項,即爲f(x)在上的FFT結果
IFFT計算步驟:
設是f(x)在上的FFT結果
(1)將擴展,使其奇數項爲,偶數項爲0,擴展到2n次
(2)使用2n階IFFT求出擴展後多項式的逆變換的值
(3)設(2)中逆變換對應的擴展多項式逆變換爲,令
還原出來的n次
大致整體思路就是擴展到2n次,然後使用上的FFT和IFFT求出上的FFT和IFFT變換
下面貼C語言代碼:
#include "pch.h"
#define _CRT_SECURE_NO_WARNINGS
#include "stdlib.h"
#include "math.h"
#include "stdio.h"
#define N 8
#define MAXN 100
#define Pi 3.1415927 //定義圓周率Pi
#define LEN sizeof(struct Compx) //定義複數結構體大小
//-----定義複數結構體-----------------------
typedef 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 sub(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 add(struct Compx a, struct Compx b)
{
struct Compx c;
c.real = a.real + b.real;
c.imag = a.imag + b.imag;
return(c);
}
void fft(Compx *a, int n, int inv);
void fft_1(Compx *a, int n, int inv);
int main()
{
int i;
int x[N] = { 0 }, y[N] = { 0 };
printf("\nN=%d\n", N);
printf("\n輸入兩個多項式的係數,輸入係數爲N多項式長度的一半\n");
printf("\n輸入第一個多項式的係數\n");
for (i = 0; i < N / 2; i++)
{
scanf("%d", &x[i]);
}
struct Compx * a = (struct Compx *)malloc(N*LEN); //爲結構體分配存儲空間
struct Compx * b = (struct Compx *)malloc(N*LEN);
struct Compx * c = (struct Compx *)malloc(N*LEN);
struct Compx * F = (struct Compx *)malloc(2*N*LEN);
//初始化=======================================
printf("\na多項式初始化:\n");
for (i = 0; i < N; i++)
{
a[i].real = x[i];
a[i].imag = 0;
printf("%.4f ", a[i].real);
printf("+%.4fj ", a[i].imag);
printf("\n");
}
/*--------------x^2n-1=0的解法----start----------*/
printf("\n--------------------------FFT---------------------------------\n");
int m = 2 * N;
int n = N;
double f[2 * N] = { 0 };
for (i = 0; i < N; i++) {
f[i] = 0.5 * x[i];
}
for (i = N; i < 2*N; i++) {
f[i] = -0.5 * x[i-N];
}
printf("\nf多項式初始化:\n");
for (i = 0; i < 2*N; i++)
{
F[i].real = f[i];
F[i].imag = 0;
printf("%.4f ", F[i].real);
printf("+%.4fj ", F[i].imag);
printf("\n");
}
fft(F, m, 1);
printf("\nF多項式FFT計算結果:\n");
for (i = 0; i < 2*N; i++)
{
printf("%.4f ", F[i].real);
printf("+%.4fj ", F[i].imag);
printf("\n");
}
for (i = 0; i < N; i++ ) {
a[i] = F[2 * i + 1];
}
printf("\n--------------------------IFFT---------------------------------\n");
fft(F, m, -1);
for (i = 0; i < m; i++) {
F[i].real = F[i].real / m;
F[i].imag = F[i].imag / m;
}
printf("\nF多項式IFFT計算結果:\n");
for (i = 0; i < 2 * N; i++)
{
printf("%.4f ", F[i].real);
printf("+%.4fj ", F[i].imag);
printf("\n");
}
//F(x)的低次
double temp_low[N] = { 0 };
double temp_high[N] = { 0 };
for (i = 0; i < N; i++)
{
temp_low[i] = F[i].real;
}
for (i = N; i < 2*N; i++)
{
temp_high[i-N] = F[i].real;
}
double res[N] = { 0 };
for (i = 0; i < N; i++)
{
res[i] = temp_low[i] - temp_high[i];
}
printf("\nIFFT計算結果:\n");
for (i = 0; i < N; i++)
{
printf("%.4f", res[i]);
printf("\n");
}
/*--------------x^2n+1=0的解法----end----------*/
//fft_1(a, N, 1);
printf("\n第一個多項式FFT計算結果:\n");
for (i = 0; i < N; i++)
{
printf("%.4f ", a[i].real);
printf("+%.4fj ", a[i].imag);
printf("\n");
}
return 0;
}
//x^n+1=0的FFT形式
void fft_1(Compx *a, int n, int inv) {
if (n == 1)return;
int mid = n / 2;
static Compx b[MAXN];
int i;
for (i = 0; i < mid; i++) {
b[i] = a[i * 2];
b[i + mid] = a[i * 2 + 1];
}
for (i = 0; i < n; i++)
a[i] = b[i];
fft(a, mid, inv);
fft(a + mid, mid, inv);//分治
for (i = 0; i < mid; i++)
{
Compx x;
x.real = cos(2 * Pi*(2*i+1) / (2*n));
x.imag = inv * sin(2 * Pi*(2 * i + 1) / (2*n));
b[i] = add(a[i], mult(x, a[i + mid]));
b[i + mid] = sub(a[i], mult(x, a[i + mid]));
}
for (i = 0; i < n; i++)
a[i] = b[i];
}
//x^n-1=0的FFT形式
void fft(Compx *a, int n, int inv) {
if (n == 1)return;
int mid = n / 2;
static Compx b[MAXN];
int i;
for (i = 0; i < mid; i++) {
b[i] = a[i * 2];
b[i + mid] = a[i * 2 + 1];
}
for (i = 0; i < n; i++)
a[i] = b[i];
fft(a, mid, inv);
fft(a + mid, mid, inv);//分治
for (i = 0; i < mid; i++)
{
Compx x;
x.real = cos(2 * Pi*i / n);
x.imag = inv * sin(2 * Pi*i / n);
b[i] = add(a[i], mult(x, a[i + mid]));
b[i + mid] = sub(a[i], mult(x, a[i + mid]));
}
for (i = 0; i < n; i++)
a[i] = b[i];
}