大整数乘法---FFT算法

 

//迭代FFT的乘法方法
// POJ 1405 Heritage
/**
 * input data mode:
 *  the number array 1,2,3,4 use base U = 2^ENTRYSIZE replace the real number
 * 1*U^0 + 2*U^1 + 3*U^2 + 4*U^3
 *
 * the output number array is the same as the input number array
 * the max term of the cirrocumulus must not be over P
 * So 2*ENTRYSIZE+log(max(mag.length)) < log(P)
 */
import java.io.*;
import java.math.*;
import java.lang.*;
import java.util.*;
import java.text.*;
public class Main {
       
    public static void main(String[] args) throws CloneNotSupportedException{
        DecimalFormat df = new DecimalFormat("0");//ENTRYSIZE = 1;
        Scanner cin = new Scanner(System.in);      
        int n = cin.nextInt();
        int mag[] = {2};
        FastInt A = new FastInt(1,mag);
        for(int i = 0; i < n;i++) {
            A.mag = cutLead0(A.mag);
            System.out.print(A.mag[A.mag.length-1]);
            for(int j = A.mag.length-2; j >= 0; j--)
                System.out.print(df.format(A.mag[j]));
            System.out.println();
            FastInt B = (FastInt)A.clone();
            subOne(B.mag);
            A = A.multiply(B);
            addOne(A.mag);              
        }
    }
   
    protected static int[] cutLead0(int []A){
        int i;
        for(i = A.length-1; i >= 0; i--)
            if(A[i] != 0) break;
        int []B = new int[i+1];
        System.arraycopy(A, 0, B, 0, i+1);
        return B;
    }
   
    protected static void addOne(int []A){
       int carry = 1;
       int po = (int)Math.pow(10, FastInt.ENTRYSIZE);
       for(int i = 0; i < A.length; i++){
           A[i] += carry;
           carry = A[i]/po;
           A[i] %= po;
       }
       if(carry > 0){
           int []B = new int [A.length+1];
           for(int i = 0; i < A.length; i++) B[i] = A[i];
           B[A.length] = carry;
           A = B;
       }
    }
   
    protected static void subOne(int []A){
       int po = (int)Math.pow(10, FastInt.ENTRYSIZE);
       A[0] -= 1;
       for(int i = 1; i < A.length; i++){
           if(A[i-1] >= 0) break;
           A[i-1] = (A[i-1] + po) % po;
           A[i]--;
       }
    }
}
class FastInt implements Cloneable{
    public final static int ENTRYSIZE = 1;          //Bits per entry in mag
    protected int[] mag;                            //magnitude in little-endian format
    protected int signum = 0;                       //neg = -1,0 = 0,pos = 1               
    public static int logN = 0; 
    public static int []reverse;
    public final static int MAXN = 134217728;       //Maximum value for n 2^27
    protected final static long P = 2013265921;     // The prime 15*2^{27}+1
    protected final static int OMEGA = 440564289;   //Root of unity 31^{15}mod P
    protected final static int TWOINV = 1006632961; //2^{-1}mod P

    @Override
    public Object clone(){
        FastInt C;
        try{
            C = (FastInt)super.clone();
        }
        catch(CloneNotSupportedException ex){
            return null;
        }
        C.mag = (int[])mag.clone();
        return C;
    }
   
    public FastInt(int signnum, int[] mag) {
        this.signum = signnum;
        this.mag = (int[])mag.clone();
    }
    
    //FFT算法迭代实现的支持方法
    protected static int makePowerOfTwo(int length) {
        int i;
        for (i = 1; i < length; i *= 2);
        return i;
    }

    protected static int[] rootsOfUnity(int n) {      //assumes n is power of 2
        int nthroot = OMEGA;
        for (int t = MAXN; t > n; t /= 2)               //Find prim. nth root of unity       
            nthroot = (int) (((long) nthroot * nthroot) % P);
        int[] roots = new int[n];
        int r = 1;                                      //r will run through all nth roots of unity
        for (int i = 0; i < n; i++) {
            roots[i] = r;
            r = (int) (((long) r * nthroot) % P);
        }
        return roots;
    }

    protected static int[] padWithZeros(int[] mag, int n) {
        int[] tmp = new int[n];
        for (int i = 0; i < mag.length; i++) {
            tmp[i] = mag[i];
        }
        for (int i = mag.length; i < n; i++) {
            tmp[i] = 0;
        }
        return tmp;
    }

    protected static void reverseRoots(int[] root) {//root[i]^-1
        int temp;
        for (int i = 1; i < (root.length + 1) / 2; i++) {
            temp = root[i];
            root[i] = root[root.length - i];
            root[root.length - i] = temp;
        }
    }
   
    protected static void bitreverse(int[] A, int logN) {
        int[] temp = new int[A.length];
        for (int i = 0; i < A.length; i++) {
            temp[reverse[i]] = A[i];
        }
        for (int i = 0; i < A.length; i++) {
            A[i] = temp[i];
        }
    }
   
    protected static int[] reverseArray(int n, int logN) {
        int[] result = new int[n];
        for (int i = 0; i < n; i++) {
            result[i] = reverse(i, logN);
        }
        return result;
    }

    protected static int reverse(int N, int logN) {
        int bit = 0;
        int result = 0;
        for (int i = 0; i < logN; i++) {        //二进制形式的倒数
            bit = N & 1;
            result = (result << 1) + bit;
            N = N >>> 1;
        }
        return result;
    }
   
    protected static int modInverse(int n) {    //assume n is power of two
        int result = 1;
        for (long twoPower = 1; twoPower < n; twoPower *= 2) { //n = 2^t
            result = (int) (((long) result * TWOINV ) % P);
        }
        return result;
    }
   
    protected static int logBaseTwo(int n) {
        int i = 0;
        for(i = 0; n > 1 ; i++)  n >>= 1;
        return i;
    }
   
    public FastInt multiply(FastInt val) {
        int n = makePowerOfTwo(Math.max(mag.length, val.mag.length)) * 2;
        logN = logBaseTwo(n);                       //log of n base 2
        reverse = reverseArray(n, logN);            // initialize reversal lookup table
        int signResult = signum * val.signum;
        int[] A = padWithZeros(mag, n);             // copies mag into A padded w/0's
        int[] B = padWithZeros(val.mag, n);         //copies val.mag into B padded @/0's
        int[] root = rootsOfUnity(n);               //creates all n roots of unity
        FFT(A, root, n);                            //leaves FFT result int A
        FFT(B, root, n);                            //leaves FFT result int B
        for (int i = 0; i < n; i++) {
            A[i] = (int) (((long) A[i] * B[i]) % P); //componet -wise multiply
        }
        reverseRoots(root);                         //reverse root to creat inverse roots
        inverseFFT(A, root, n);                     //leaves inverse FFT resul in A
        propagateCarries(A);
        return new FastInt(signResult, A);
    }       
    //FFT 算法的迭代实现
    public static void FFT(int[] A, int[] root, int n) {
        int prod, term, index;                              //valus for common subexpressions
        int subsize = 1;                                    //subproblem size;
        bitreverse(A, logN);
        for (int lev = 1; lev <= logN; lev++) {
            subsize *= 2;
            for (int base = 0; base < n - 1; base += subsize) {//iterate subproblems
                int j = subsize / 2;
                int rootIndex = A.length / subsize;
                for (int i = 0; i < j; i++) {
                    index = base + i;
                    prod = (int) (((long) root[i * rootIndex] * A[index + j]) % P);
                    term = A[index];
                    A[index + j] = (int) (((long) term + P - prod) % P);
                    A[index] = (int) (((long) term + prod) % P);
                }
            }
        }
    }

    public static void inverseFFT(int[] A, int[] root, int n) {
        int inverseN = modInverse(n); //n^(-1)
        FFT(A, root, n);
        for (int i = 0; i < n; i++) {
            A[i] = (int) (((long) A[i] * inverseN) % P);
        }
    }
   
    protected static void propagateCarries(int[] A) {
        int carry = 0;
        int po = (int)Math.pow(10,ENTRYSIZE);
        for (int i = 0; i < A.length; i++) {
            carry = A[i]; A[i] = 0;
            for(int j = 0; carry != 0; j++){              
                A[i+j] += carry%po;
                carry /= po;
            }
        }//convert A to right no. of bits/entry
     }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值