当前位置:   article > 正文

FFT(快速傅里叶变换)的介绍及其C++实现_多项式乘法傅立叶变换c++

多项式乘法傅立叶变换c++

1、FFT的介绍

快速傅里叶变换 (Fast Fourier Transform)**,即利用计算机计算离散傅里叶变换(DFT)的高效、快速计算方法的统称,简称FFT,于1965年由J.W.库利和T.W.图基提出。

对于多项式

f(x)=\sum_{i=0}^{n}a_ix^i,g(x)=\sum_{i=0}^{n}b_ix^i

定义其乘积fg

f(x)=\sum_{i=0}^{n}a_ix^i,g(x)=\sum_{i=0}^{n}b_ix^i

显然我们可以以 O(n2) 的复杂度计算这个乘积的每一项的系数。

但FFT可以以 O(nlog⁡n) 的时间复杂度来计算这个乘积。

自1965年提出至今,FFT算法在一维的信号处理和二维的图像处理中都起到了重要的作用,在人工智能、自动化等领域都有着不可替代的作用

2、FFT的C++实现

FFT的具体实现方法有很多,这里举一个递归实现的方法

  1. #include <bits/stdc++.h>
  2. const int MAX_COEFFICIENTS = 1 << 22;
  3. const double EPSILON = 1e-6, PI = acos(-1.0);
  4. using namespace std;
  5. complex<double> coefficientsA[MAX_COEFFICIENTS], coefficientsB[MAX_COEFFICIENTS];
  6. int degreeA, degreeB;
  7. // FFT: Fast Fourier Transform
  8. // Parameters:
  9. //   - coefficients: Array representing the coefficients of a polynomial
  10. //   - degree: Degree of the polynomial
  11. //   - inv: If inv is 1, perform FFT; if inv is -1, perform IFFT
  12. void FFT(complex<double> *coefficients, int degree, int inv) {
  13.    if (degree == 1) // If there is only one term, return directly
  14.        return;
  15.    int mid = degree / 2;
  16.    // Split the polynomial into two parts
  17.    complex<double> A1[mid + 1], A2[mid + 1];
  18.    for (int i = 0; i <= degree; i += 2) {
  19.        A1[i / 2] = coefficients[i];
  20.        A2[i / 2] = coefficients[i + 1];
  21.   }
  22.    // Recursively apply FFT or IFFT
  23.    FFT(A1, mid, inv);
  24.    FFT(A2, mid, inv);
  25.    complex<double> w0(1, 0), wn(cos(2 * PI / degree), inv * sin(2 * PI / degree)); // Unit root
  26.    // Merge the polynomials
  27.    for (int i = 0; i < mid; ++i, w0 *= wn) {
  28.        coefficients[i] = A1[i] + w0 * A2[i];
  29.        coefficients[i + degree / 2] = A1[i] - w0 * A2[i];
  30.   }
  31. }
  32. int main() {
  33.    scanf("%d%d", &degreeA, &degreeB);
  34.    // Input coefficients for the first polynomial
  35.    for (int i = 0; i <= degreeA; ++i) {
  36.        double x;
  37.        scanf("%lf", &x);
  38.        coefficientsA[i].real(x);
  39.   }
  40.    // Input coefficients for the second polynomial
  41.    for (int i = 0; i <= degreeB; ++i) {
  42.        double x;
  43.        scanf("%lf", &x);
  44.        coefficientsB[i].real(x);
  45.   }
  46.    int length = 1 << max((int)ceil(log2(degreeA + degreeB)), 1); // Determine the length for FFT
  47.    FFT(coefficientsA, length, 1); // Convert coefficient representation to point-value representation
  48.    FFT(coefficientsB, length, 1);
  49.    // Perform polynomial multiplication in O(n) time
  50.    for (int i = 0; i <= length; ++i)
  51.        coefficientsA[i] = coefficientsA[i] * coefficientsB[i];
  52.    FFT(coefficientsA, length, -1); // Convert point-value representation back to coefficient representation
  53.    // Output the result
  54.    for (int i = 0; i <= degreeA + degreeB; ++i)
  55.        printf("%.0f ", coefficientsA[i].real() / length + EPSILON); // Divide by length; EPSILON to handle precision issues
  56.    return 0;
  57. }

以下是针对这个递归实现的优化

  1. #include <bits/stdc++.h>
  2. const int MAX_COEFFICIENTS = 1 << 22;
  3. const double EPSILON = 1e-6, PI = acos(-1.0);
  4. using namespace std;
  5. complex<double> coefficientsA[MAX_COEFFICIENTS], coefficientsB[MAX_COEFFICIENTS];
  6. int degreeA, degreeB;
  7. // FFT: 快速傅里叶变换
  8. // 参数:
  9. //   - coefficients: 表示多项式的系数数组
  10. //   - degree: 多项式的阶数
  11. //   - inv: 如果 inv 为 1,执行 FFT;如果 inv 为 -1,执行 IFFT
  12. void FFT(complex<double> *coefficients, int degree, int inv) {
  13.    // 位反转置换
  14.    for (int i = 1, j = 0; i < degree; ++i) {
  15.        for (int k = degree >> 1; (j ^= k) < k; k >>= 1);
  16.        if (i < j) swap(coefficients[i], coefficients[j]);
  17.   }
  18.    // Cooley-Tukey算法迭代过程
  19.    for (int len = 2; len <= degree; len <<= 1) {
  20.        double ang = inv * 2 * PI / len;
  21.        complex<double> wlen(cos(ang), sin(ang));
  22.        for (int i = 0; i < degree; i += len) {
  23.            complex<double> w(1, 0);
  24.            for (int j = 0, mid = len >> 1; j < mid; ++j) {
  25.                complex<double> u = coefficients[i + j], v = w * coefficients[i + j + mid];
  26.                coefficients[i + j] = u + v;
  27.                coefficients[i + j + mid] = u - v;
  28.                w *= wlen;
  29.           }
  30.       }
  31.   }
  32. }
  33. int main() {
  34.    scanf("%d%d", &degreeA, &degreeB);
  35.    // 输入第一个多项式的系数
  36.    for (int i = 0; i <= degreeA; ++i) {
  37.        double x;
  38.        scanf("%lf", &x);
  39.        coefficientsA[i].real(x);
  40.   }
  41.    // 输入第二个多项式的系数
  42.    for (int i = 0; i <= degreeB; ++i) {
  43.        double x;
  44.        scanf("%lf", &x);
  45.        coefficientsB[i].real(x);
  46.   }
  47.    int length = 1 << max((int)ceil(log2(degreeA + degreeB)), 1); // 确定 FFT 的长度
  48.    FFT(coefficientsA, length, 1); // 将系数表示转换为点值表示
  49.    FFT(coefficientsB, length, 1);
  50.    // 在 O(n) 时间内执行多项式乘法
  51.    for (int i = 0; i <= length; ++i)
  52.        coefficientsA[i] = coefficientsA[i] * coefficientsB[i];
  53.    FFT(coefficientsA, length, -1); // 将点值表示转换回系数表示
  54.    // 输出结果
  55.    for (int i = 0; i <= degreeA + degreeB; ++i)
  56.        printf("%.0f ", coefficientsA[i].real() / length + EPSILON); // 除以长度;EPSILON 用于处理精度问题
  57.    return 0;
  58. }

优化点:

  1. 位反转置换(Bit-reverse permutation): 避免了递归过程中的重复计算,通过位反转置换一次性完成了重新排列。

  2. Cooley-Tukey算法的迭代实现: 使用迭代而非递归方式,减少了递归调用的开销。

  3. 减少内存使用: 不再需要额外的临时数组,直接在原数组上进行计算,减少了内存占用。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/105019?site
推荐阅读
相关标签
  

闽ICP备14008679号