SteveHawk's Blog

FFT解大整数乘法



1. 代码文件说明

提交的代码包括两个文件夹,fft 和 judge。fft 文件夹包括的是可独立运行的 fft 求大数乘法的程序(做了输入输出重定向),以及实际提交于 Leetcode 的代码。judge 文件夹包含了三个数据文件(test.data 为十组本地测试数据,ans.data 为正确答案,fftans.data 为 fft.exe 的运行输出结果),两个 python 文件(data.py 为生成测试数据和答案的脚本,judge.py 为判断结果是否正确的脚本)。

代码放在文末。

2. 求解思想

3. 代码执行结果

代码

fft/fft.cpp

  1#include <cstdio>
  2#include <iostream>
  3#include <cmath>
  4#include <cstring>
  5#include <algorithm>
  6
  7using namespace std;
  8
  9const double PI = acos(-1.0);
 10
 11// 复数结构体
 12struct Complex{
 13    double x, y;     // 实部和虚部 x + yi
 14    Complex(double _x = 0.0, double _y = 0.0){
 15        x = _x;
 16        y = _y;
 17    }
 18    Complex operator - (const Complex &b) const{
 19        return Complex(x - b.x, y - b.y);
 20    }
 21    Complex operator + (const Complex &b) const{
 22        return Complex(x + b.x, y + b.y);
 23    }
 24    Complex operator * (const Complex &b) const{
 25        return Complex(x*b.x - y*b.y, x*b.y + y*b.x);
 26    }
 27};
 28
 29// FFT 和 IFFT 前的反转变换。
 30// 位置 i 和 (i 二进制反转后位置)互换
 31// len 必须是 2 的幂
 32void change(Complex y[], int len){
 33    int i, j, k;
 34    for(i = 1, j = len / 2; i < len - 1; i++){
 35        if(i < j) swap(y[i], y[j]);
 36        // 交换互为小标反转的元素,i < j 保证交换一次
 37        // i 做正常的 +1,j 左反转类型的 +1,始终保持 i 和 j 是反转的
 38        k = len / 2;
 39        while(j >= k){
 40            j -= k;
 41            k /= 2;
 42        }
 43        if(j < k) j += k;
 44    }
 45}
 46
 47// FFT
 48// len 必须为 2 的幂,
 49// on == 1 时是 DFT,on == -1 时是 IDFT
 50void fft(Complex y[], int len, int on){
 51    change(y, len);
 52    for(int h = 2; h <= len; h *= 2){
 53        Complex wn(cos(-on * 2*PI / h), sin(-on * 2*PI / h));
 54        for(int j = 0; j < len; j += h){
 55            Complex w(1, 0);
 56            for(int k = j; k < j + h/2; k++){
 57                Complex u = y[k];
 58                Complex t = w * y[k + h/2];
 59                y[k] = u + t;
 60                y[k + h/2] = u - t;
 61                w = w * wn;
 62            }
 63        }
 64    }
 65    if(on == -1)
 66        for(int i = 0; i < len; i++)
 67            y[i].x /= len;
 68}
 69
 70const int MAXN = 200010;
 71Complex x1[MAXN], x2[MAXN];
 72char str1[MAXN / 2], str2[MAXN / 2];
 73int sum[MAXN];
 74
 75int main(){
 76    freopen("test.data", "r", stdin);
 77    freopen("fftans.data", "w", stdout);
 78
 79    // 输入两个大数字符串
 80    while(scanf("%s%s", str1, str2)!=EOF){
 81        int len1 = strlen(str1);
 82        int len2 = strlen(str2);
 83
 84        int len = 1;
 85        while(len < len1 * 2 || len < len2 * 2) len *= 2;
 86
 87        // 把字符串转化为复数数组并补前导 0 至 2 的幂
 88        for(int i = 0; i < len1; i++)
 89            x1[i] = Complex(str1[len1 - 1 - i] - '0', 0);
 90        for(int i = len1; i < len; i++)
 91            x1[i] = Complex(0, 0);
 92
 93        for(int i = 0; i < len2; i++)
 94            x2[i] = Complex(str2[len2 - 1 - i] - '0', 0);
 95        for(int i = len2; i < len; i++)
 96            x2[i] = Complex(0, 0);
 97        
 98        // 求DFT
 99        fft(x1, len, 1);
100        fft(x2, len, 1);
101
102        // 相乘
103        for(int i = 0; i < len; i++)
104            x1[i] = x1[i] * x2[i];
105        
106        // IDFT
107        fft(x1, len, -1);
108
109        // 转化为整数值
110        for(int i = 0; i < len; i++)
111            sum[i] = (int)(x1[i].x + 0.5);
112        for(int i = 0; i < len; i++){
113            sum[i+1] += sum[i] / 10;
114            sum[i] %= 10;
115        }
116
117        // 输出结果
118        len = len1 + len2 - 1;
119        while(sum[len] <= 0 && len > 0) len--;
120        for(int i = len; i >= 0; i--)
121            printf("%c", sum[i] + '0');
122        printf("\n");
123    }
124    return 0;
125}

fft/leetcode_upload.cpp

  1class Solution {
  2public:
  3    double PI = acos(-1.0);
  4    // 复数结构体
  5    struct Complex{
  6        double x, y;     // 实部和虚部 x + yi
  7        Complex(double _x = 0.0, double _y = 0.0){
  8            x = _x;
  9            y = _y;
 10        }
 11        Complex operator - (const Complex &b) const{
 12            return Complex(x - b.x, y - b.y);
 13        }
 14        Complex operator + (const Complex &b) const{
 15            return Complex(x + b.x, y + b.y);
 16        }
 17        Complex operator * (const Complex &b) const{
 18            return Complex(x*b.x - y*b.y, x*b.y + y*b.x);
 19        }
 20    };
 21    // FFT 和 IFFT 前的反转变换。
 22    // 位置 i 和 (i 二进制反转后位置)互换
 23    // len 必须是 2 的幂
 24    void change(Complex y[], int len){
 25        int i, j, k;
 26        for(i = 1, j = len / 2; i < len - 1; i++){
 27            if(i < j) swap(y[i], y[j]);
 28            // 交换互为小标反转的元素,i < j 保证交换一次
 29            // i 做正常的 +1,j 左反转类型的 +1,始终保持 i 和 j 是反转的
 30            k = len / 2;
 31            while(j >= k){
 32                j -= k;
 33                k /= 2;
 34            }
 35            if(j < k) j += k;
 36        }
 37    }
 38
 39    // FFT
 40    // len 必须为 2 的幂,
 41    // on == 1 时是 DFT,on == -1 时是 IDFT
 42    void fft(Complex y[], int len, int on){
 43        change(y, len);
 44        for(int h = 2; h <= len; h *= 2){
 45            Complex wn(cos(-on * 2*PI / h), sin(-on * 2*PI / h));
 46            for(int j = 0; j < len; j += h){
 47                Complex w(1, 0);
 48                for(int k = j; k < j + h/2; k++){
 49                    Complex u = y[k];
 50                    Complex t = w * y[k + h/2];
 51                    y[k] = u + t;
 52                    y[k + h/2] = u - t;
 53                    w = w * wn;
 54                }
 55            }
 56        }
 57        if(on == -1)
 58            for(int i = 0; i < len; i++)
 59                y[i].x /= len;
 60    }
 61
 62    Complex x1[200010], x2[200010];
 63    char str1[100005], str2[100005];
 64    int sum[200010];
 65
 66    string multiply(string num1, string num2) {
 67        // 输入两个大数字符串
 68        strcpy(str1, num1.c_str());
 69        strcpy(str2, num2.c_str());
 70
 71        int len1 = strlen(str1);
 72        int len2 = strlen(str2);
 73
 74        int len = 1;
 75        while(len < len1 * 2 || len < len2 * 2) len *= 2;
 76
 77        // 把字符串转化为复数数组
 78        for(int i = 0; i < len1; i++)
 79            x1[i] = Complex(str1[len1 - 1 - i] - '0', 0);
 80        for(int i = len1; i < len; i++)
 81            x1[i] = Complex(0, 0);
 82        for(int i = 0; i < len2; i++)
 83            x2[i] = Complex(str2[len2 - 1 - i] - '0', 0);
 84        for(int i = len2; i < len; i++)
 85            x2[i] = Complex(0, 0);
 86        
 87        // 求DFT
 88        fft(x1, len, 1);
 89        fft(x2, len, 1);
 90
 91        // 相乘
 92        for(int i = 0; i < len; i++)
 93            x1[i] = x1[i] * x2[i];
 94        
 95        // IDFT
 96        fft(x1, len, -1);
 97
 98        // 转化为整数值
 99        for(int i = 0; i < len; i++)
100            sum[i] = (int)(x1[i].x + 0.5);
101        for(int i = 0; i < len; i++){
102            sum[i+1] += sum[i] / 10;
103            sum[i] %= 10;
104        }
105
106        // 输出结果
107        len = len1 + len2 - 1;
108        while(sum[len] <= 0 && len > 0) len--;
109        string ans;
110        for(int i = len; i >= 0; i--)
111            ans.append(1, char(sum[i] + '0'));
112        return ans;
113    }
114};

judge/data.py

 1from random import randint
 2
 3test = open("test.data", 'w')
 4ans = open("ans.data", 'w')
 5
 6last = str()
 7temp = str()
 8
 9for i in range(20):
10    last = temp
11    temp = str(randint(1, 9))
12    for j in range(99):
13        temp += str(randint(0, 9))
14    test.write(temp)
15    if i % 2 == 1:
16        test.write("\n")
17        ans.write(str(int(temp) * int(last)) + "\n")
18    else:
19        test.write(" ")
20
21test.close()

judge/judge.py

 1fftans = open("fftans.data", "r").readlines()
 2ans = open("ans.data", "r").readlines()
 3
 4if len(fftans) != len(ans):
 5    print("Fail")
 6
 7for i in range(len(fftans)):
 8    if fftans[i] != ans[i]:
 9        print("Fail ! No. {}".format(i + 1))
10        break
11print("Success !")

#courses
本文总字数 2990
本文阅读量
本站访客量

↪ reply by email