PloadyFree

BigInt + FFT

Feb 21st, 2019
220
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 5.01 KB | None | 0 0
  1.     static class BigNumber {
  2.         int[] a;
  3.         //fft multiplication fails when packLen > 5
  4.         static final int packLen = 5;
  5.         static final int mod = (int) Math.round(Math.pow(10, packLen));
  6.         static final String fmt = "%0" + packLen + "d";
  7.  
  8.         BigNumber(int[] a) {
  9.             this.a = trim(a);
  10.         }
  11.  
  12.         BigNumber(String s) {
  13.             this(fromString(s));
  14.         }
  15.  
  16.         static int[] fromString(String s) {
  17.             int[] a = new int[(s.length() + packLen - 1) / packLen];
  18.             for (int i = s.length() - 1, at = 0; i >= 0; i -= packLen, at++) {
  19.                 int j = Math.max(0, i - packLen + 1);
  20.                 int x = 0;
  21.                 for (int k = j; k <= i; k++) x = x * 10 + s.charAt(k) - '0';
  22.                 a[at] = x;
  23.             }
  24.             return a;
  25.         }
  26.  
  27.         BigNumber multiply(BigNumber other) {
  28.             long[] res = new FFT().multiply(a, other.a);
  29.             int[] ans = new int[res.length + 1];
  30.             int carry = 0;
  31.             for (int i = 0; i < res.length; i++) {
  32.                 long x = res[i] + carry;
  33.                 ans[i] = (int) (x % mod);
  34.                 carry = (int) (x / mod);
  35.             }
  36.             ans[res.length] = carry;
  37.             return new BigNumber(ans);
  38.         }
  39.  
  40.         int[] trim(int[] a) {
  41.             int sz = a.length;
  42.             while (sz > 1 && a[sz - 1] == 0) sz--;
  43.             return Arrays.copyOfRange(a, 0, sz);
  44.         }
  45.  
  46.         @Override
  47.         public String toString() {
  48.             StringBuilder sb = new StringBuilder();
  49.             for (int i = a.length - 1; i >= 0; i--) sb.append(String.format(fmt, a[i]));
  50.             while (sb.length() > 1 && sb.charAt(0) == '0') sb.deleteCharAt(0);
  51.             return sb.toString();
  52.         }
  53.     }
  54.  
  55.     static class FFT {
  56.         void fft(double[] real, double[] imag, boolean inv) {
  57.             int n = real.length;
  58.             int m = 0;
  59.             while (1 << m < n) m++;
  60.  
  61.             int[] rev = new int[n];
  62.             for (int i = 1, j = -1; i < n; i++) {
  63.                 if ((i & (i - 1)) == 0) j++;
  64.                 rev[i] = rev[i ^ (1 << j)] | (1 << (m - 1 - j));
  65.             }
  66.             for (int i = 0; i < n; i++) {
  67.                 if (i < rev[i]) {
  68.                     swap(real, i, rev[i]);
  69.                     swap(imag, i, rev[i]);
  70.                 }
  71.             }
  72.  
  73.             for (int len = 1; len < n; len <<= 1) {
  74.                 double root = Math.PI / len;
  75.                 if (inv) root = -root;
  76.                 double rootReal = Math.cos(root);
  77.                 double rootImag = Math.sin(root);
  78.                 for (int i = 0; i < n; i += len * 2) {
  79.                     double wReal = 1;
  80.                     double wImag = 0;
  81.                     for (int j = 0; j < len; j++) {
  82.                         double real1 = real[i + j];
  83.                         double imag1 = imag[i + j];
  84.                         double real2 = real[i + j + len];
  85.                         double imag2 = imag[i + j + len];
  86.                         double real3 = real2 * wReal - imag2 * wImag;
  87.                         double imag3 = real2 * wImag + imag2 * wReal;
  88.                         real[i + j] = real1 + real3;
  89.                         imag[i + j] = imag1 + imag3;
  90.                         real[i + j + len] = real1 - real3;
  91.                         imag[i + j + len] = imag1 - imag3;
  92.                         double nextwr = wReal * rootReal - wImag * rootImag;
  93.                         double nextwi = wReal * rootImag + wImag * rootReal;
  94.                         wReal = nextwr;
  95.                         wImag = nextwi;
  96.                     }
  97.                 }
  98.             }
  99.  
  100.             if (inv) {
  101.                 for (int i = 0; i < n; i++) {
  102.                     real[i] /= n;
  103.                     imag[i] /= n;
  104.                 }
  105.             }
  106.         }
  107.  
  108.         void swap(double[] a, int i, int j) {
  109.             double t = a[i];
  110.             a[i] = a[j];
  111.             a[j] = t;
  112.         }
  113.  
  114.         double[] copy(int[] a, int n) {
  115.             double[] b = new double[n];
  116.             for (int i = 0; i < a.length; i++) b[i] = a[i];
  117.             return b;
  118.         }
  119.  
  120.         long[] multiply(int[] a, int[] b) {
  121.             int n = Math.max(1, Integer.highestOneBit(Math.max(a.length, b.length) - 1) << 2);
  122.             double[] aReal = copy(a, n);
  123.             double[] aImag = new double[n];
  124.             double[] bReal = copy(b, n);
  125.             double[] bImag = new double[n];
  126.             fft(aReal, aImag, false);
  127.             fft(bReal, bImag, false);
  128.             for (int i = 0; i < n; i++) {
  129.                 double real = aReal[i] * bReal[i] - aImag[i] * bImag[i];
  130.                 double imag = aReal[i] * bImag[i] + aImag[i] * bReal[i];
  131.                 aReal[i] = real;
  132.                 aImag[i] = imag;
  133.             }
  134.             fft(aReal, aImag, true);
  135.             long[] res = new long[n];
  136.             for (int i = 0; i < res.length; i++) res[i] = Math.round(aReal[i]);
  137.             return res;
  138.         }
  139.     }
Advertisement
Add Comment
Please, Sign In to add comment