/* * Copyright (c) 2009-2015 * IT-Consulting Stephan Schloepke (http://www.schloepke.de/) * klemm software consulting Mirko Klemm (http://www.klemm-scs.com/) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.jbasics.math.obsolete; import java.util.concurrent.Callable; @SuppressWarnings("unused") public class Multiplier implements Callable<int[]> { private static final long INT_MASK = 0xffffffffL; private final int[] x; private final int[] y; private final int[] z; private final int[] zAdd; private final int[] zAdd2; public Multiplier(int[] x, int[] y) { if (x == null || y == null || x.length == 0 || y.length == 0) { throw new IllegalArgumentException("Null or empty parameter: x | y"); } if (x.length < y.length) { this.x = y; this.y = x; } else { this.x = x; this.y = y; } this.z = new int[this.x.length + this.y.length]; // this.zSub1 = new int[this.z.length]; // this.zSub2 = new int[this.z.length]; this.zAdd = new int[this.z.length]; this.zAdd2 = new int[this.z.length]; } private void procAdd(int[] x, int x0, int xLen, int[] y, int y0, int yLen, int[] z, int z0, int zLen) { for (int i = 0; i < xLen; i++) { // z[] } } private void procMul(int[] x, int x0, int xLen, int[] y, int y0, int yLen, int[] z, int z0, int zLen) { if (xLen > 1) { int split = (xLen + 1) >> 1; procMul(x, x0, split, y, y0, split, z, z0, split << 1); procMul(x, x0 + split, split, y, y0 + split, split, z, z0 + (split << 1), split << 1); int[] temp = new int[zLen - 1]; } } public int[] call() throws Exception { for (int i = 0; i < this.y.length; i++) { long t = this.x[i] * this.y[i]; this.z[i << 2] = (int) t; this.z[(i << 2) + 1] = (int) (t >>> 32); } int[] z = new int[this.x.length + this.y.length]; procMul(this.x, 0, this.x.length, this.y, 0, this.y.length, z, 0, z.length); return z; // if (this.x.length == 1) { // long t = this.x[0] * this.y[0]; // return new int[] { (int) t, (int) (t >>> 32) }; // } else if (this.y.length == 1) { // int z[] = new int[this.x.length + 1]; // long p = 0; // for (int i = 0; i < this.x.length; i++) { // z[i] = (int) (p = this.x[i] * this.y[0] + (p >>> 32)); // } // z[z.length - 1] = (int) (p >>> 32); // return z; // } else if (this.x.length == 2 && this.y.length == 2) { // int[] z = new int[4]; // long p1 = this.x[0] * this.y[0]; // z[0] = (int)p1; // z[1] = (int)(p1 >>> 32); // long p2 = this.x[1] * this.y[1]; // z[2] = (int)p2; // z[3] = (int)(p2 >>> 32); // long p3 = this.x[0] * this.y[1] + z[1]; // z[1] = (int)p3; // p3 = (p3 >>> 32) + z[2]; // // } // // Both are two so direct karatsuba // long p1 = this.x[0] * this.y[0]; // long p2 = this.x[1] * this.y[1]; // long p3a = this.x[0] + this.x[1]; // long p3b = this.y[0] + this.y[1]; // long p31 = (p3a & INT_MASK) * (p3b & INT_MASK); // long p32 = p31 >>> 32; // if ((p3a >>> 32) > 0) { // p32 += p3a & INT_MASK; // } // if ((p3b >>> 32) > 0) { // p32 += p3b & INT_MASK; // } // // // long p3 = (this.x[0] + this.x[1]) * (this.y[0] + this.y[1]); // TODO: This produces a problem // because it becomes bigger than long! // return new int[] { // // } else { // throw new UnsupportedOperationException("Overflow caused by to big numbers to multiply"); // } } // private int[] multiply(int[] x, int[] y, int[] z) { // if (x.length == 1 && y.length == 1) { // long t = x[0] * y[0]; // int zReqLen = t >>> 32 != 0 ? 2 : 1; // if (z == null || z.length < zReqLen) { // z = new int[zReqLen]; // } // z[0] = (int) t; // if (z.length > 1) { // z[1] = (int) (t >>> 32); // } // } // if (x.length == 1 || y.length == 1) { // // } // // return z; // } // // 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 w/ 0's // int[] root = rootsOfUnity(n); // creates all n roots of unity // FFT(A, root, n); // Leaves FFT result in A // FFT(B, root, n); // Leaves FFT result in B // for (int i = 0; i & ltn; i++) // A[i] = (int) (((long) A[i] * B[i]) % P); // Component-wise multiply // reverseRoots(root); // Reverse roots to create inverse roots // inverseFFT(A, root, n); // Leaves inverse FFT result in A // propagateCarries(A); // Convert A to right no. of bits/entry // return new FastInt(signResult, A); // } // // public static void FFT(int[] A, int[] root, int n) { // int prod, term, index; // Values for common subexpressions // int subSize = 1; // Subproblem size // bitReverse(A, logN); // Permute A by bit reversal table // for (int lev = 1; lev <= logN; lev++) { // subSize *= 2; // Double the subproblem size. // 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 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 int signum = 0; // neg = -1, 0 = 0, pos = 1 // protected int[] mag; // magnitude in little-endian format // public final static int MAXN = 134217728; // 2^{27} // public final static int ENTRYSIZE = 10; // Bits per entry in mag // 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 // // public BigInt multiply(BigInt val) { // int n = makePowerOfTwo(Math.max(mag.length, val.mag.length)) * 2; // 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 w/ 0's // int[] root = rootsOfUnity(n); // creates all n roots of unity // int[] C = new int[n]; // result array for A*B // int[] AF = new int[n]; // result array for FFT of A // int[] BF = new int[n]; // result array for FFT of B // FFT(A, root, n, 0, AF); // FFT(B, root, n, 0, BF); // for (int i = 0; i < n; i++) // AF[i] = (int) (((long) AF[i] * (long) BF[i]) % P); // Component multiply // reverseRoots(root); // Reverse roots to create inverse roots // inverseFFT(AF, root, n, 0, C); // Leaves inverse FFT result in C // propagateCarries(C); // Convert C to right no. bits per entry // return new BigInt(signResult, C); // } // // public static void FFT(int[] A, int[] root, int n, int base, int[] Y) { // int prod; // if (n == 1) { // Y[base] = A[base]; // return; // } // inverseShuffle(A, n, base); // inverse shuffle to separate evens and odds // FFT(A, root, n / 2, base, Y); // results in Y[base] to Y[base+n/2-1] // FFT(A, root, n / 2, base + n / 2, Y); // results in Y[base+n/2] to Y[base+n-1] // int j = A.length / n; // for (int i = 0; i < n / 2; i++) { // prod = (int) (((long) root[i * j] * Y[base + n / 2 + i]) % P); // Y[base + n / 2 + i] = (int) (((long) Y[base + i] + P - prod) % P); // Y[base + i] = (int) (((long) Y[base + i] + prod) % P); // } // } // // public static void inverseFFT(int[] A, int[] root, int n, int base, int[] Y) { // int inverseN = modInverse(n); // n^{-1} // FFT(A, root, n, base, Y); // for (int i = 0; i < n; i++) // Y[i] = (int) (((long) Y[i] * inverseN) % P); // } // // protected static int modInverse(int n) { // assumes n is power of two // int result = 1; // for (long twoPower = 1; twoPower < n; twoPower *= 2) // result = (int) (((long) result * TWOINV) % P); // return result; // } // // protected static void inverseShuffle(int[] A, int n, int base) { // int shift; // int[] sp = new int[n]; // for (int i = 0; i < n / 2; i++) { // Unshuffle A into the scratch space // shift = base + 2 * i; // sp[i] = A[shift]; // an even index // sp[i + n / 2] = A[shift + 1]; // an odd index // } // for (int i = 0; i < n; i++) // A[base + i] = sp[i]; // copy back to A // } // // 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 void propagateCarries(int[] A) { // int i, carry; // carry = 0; // for (i = 0; i < A.length; i++) { // A[i] = A[i] + carry; // carry = A[i] >>> ENTRYSIZE; // A[i] = A[i] - (carry << ENTRYSIZE); // } // } }