/// <summary> /// Multiplies the polynomial with a <c>TernaryPolynomial</c>, taking the indices mod N and the values mod 2048. /// </summary> /// /// <param name="Factor">The polynomial factor</param> /// /// <returns>The multiplication product</returns> public LongPolynomial5 Multiply(ITernaryPolynomial Factor) { long[][] prod = ArrayUtils.CreateJagged<long[][]>(5, _coeffs.Length + (Factor.Size() + 4) / 5 - 1); int[] pIdx = Factor.GetOnes(); // multiply ones for (int i = 0; i < pIdx.Length; i++) { int cIdx = pIdx[i] / 5; int m = pIdx[i] - cIdx * 5; // m = pIdx % 5 for (int j = 0; j < _coeffs.Length; j++) { prod[m][cIdx] = (prod[m][cIdx] + _coeffs[j]) & 0x7FF7FF7FF7FF7FFL; cIdx++; } } pIdx = Factor.GetNegOnes(); // multiply negative ones for (int i = 0; i < pIdx.Length; i++) { int cIdx = pIdx[i] / 5; int m = pIdx[i] - cIdx * 5; // m = pIdx % 5 for (int j = 0; j < _coeffs.Length; j++) { prod[m][cIdx] = (0x800800800800800L + prod[m][cIdx] - _coeffs[j]) & 0x7FF7FF7FF7FF7FFL; cIdx++; } } // combine shifted coefficients (5 arrays) into a single array of length prod[*].Length+1 long[] cCoeffs = prod[0].CopyOf(prod[0].Length + 1); for (int m = 1; m <= 4; m++) { int shift = m * 12; int shift60 = 60 - shift; long mask = (1L << shift60) - 1; int pLen = prod[m].Length; for (int i = 0; i < pLen; i++) { long upper, lower; upper = prod[m][i] >> shift60; lower = prod[m][i] & mask; cCoeffs[i] = (cCoeffs[i] + (lower << shift)) & 0x7FF7FF7FF7FF7FFL; int nextIdx = i + 1; cCoeffs[nextIdx] = (cCoeffs[nextIdx] + upper) & 0x7FF7FF7FF7FF7FFL; } } // reduce indices of cCoeffs modulo numCoeffs int shift2 = 12 * (_numCoeffs % 5); for (int cIdx = _coeffs.Length - 1; cIdx < cCoeffs.Length; cIdx++) { long iCoeff; // coefficient to shift into the [0..numCoeffs-1] range int newIdx; if (cIdx == _coeffs.Length - 1) { iCoeff = _numCoeffs == 5 ? 0 : cCoeffs[cIdx] >> shift2; newIdx = 0; } else { iCoeff = cCoeffs[cIdx]; newIdx = cIdx * 5 - _numCoeffs; } int base1 = newIdx / 5; int m = newIdx - base1 * 5; // m = newIdx % 5 long lower = iCoeff << (12 * m); long upper = iCoeff >> (12 * (5 - m)); cCoeffs[base1] = (cCoeffs[base1] + lower) & 0x7FF7FF7FF7FF7FFL; int base2 = base1 + 1; if (base2 < _coeffs.Length) cCoeffs[base2] = (cCoeffs[base2] + upper) & 0x7FF7FF7FF7FF7FFL; } return new LongPolynomial5(cCoeffs, _numCoeffs); }
/// <summary> /// Adds a <c>TernaryPolynomial</c> which must not have more coefficients than <c>this</c> polynomial. /// </summary> /// /// <param name="B">Another polynomial</param> public void Add(ITernaryPolynomial B) { foreach (int n in B.GetOnes()) Coeffs[n]++; foreach (int n in B.GetNegOnes()) Coeffs[n]--; }
/// <summary> /// Multiplies the polynomial with a <c>TernaryPolynomial</c>, taking the indices mod N and the values mod 2048. /// </summary> /// /// <param name="Factor">The polynomial factor</param> /// /// <returns>The multiplication product</returns> public LongPolynomial5 Multiply(ITernaryPolynomial Factor) { long[][] prod = ArrayUtils.CreateJagged <long[][]>(5, _coeffs.Length + (Factor.Size() + 4) / 5 - 1); int[] pIdx = Factor.GetOnes(); // multiply ones for (int i = 0; i < pIdx.Length; i++) { int cIdx = pIdx[i] / 5; int m = pIdx[i] - cIdx * 5; // m = pIdx % 5 for (int j = 0; j < _coeffs.Length; j++) { prod[m][cIdx] = (prod[m][cIdx] + _coeffs[j]) & 0x7FF7FF7FF7FF7FFL; cIdx++; } } pIdx = Factor.GetNegOnes(); // multiply negative ones for (int i = 0; i < pIdx.Length; i++) { int cIdx = pIdx[i] / 5; int m = pIdx[i] - cIdx * 5; // m = pIdx % 5 for (int j = 0; j < _coeffs.Length; j++) { prod[m][cIdx] = (0x800800800800800L + prod[m][cIdx] - _coeffs[j]) & 0x7FF7FF7FF7FF7FFL; cIdx++; } } // combine shifted coefficients (5 arrays) into a single array of length prod[*].Length+1 long[] cCoeffs = prod[0].CopyOf(prod[0].Length + 1); for (int m = 1; m <= 4; m++) { int shift = m * 12; int shift60 = 60 - shift; long mask = (1L << shift60) - 1; int pLen = prod[m].Length; for (int i = 0; i < pLen; i++) { long upper, lower; upper = prod[m][i] >> shift60; lower = prod[m][i] & mask; cCoeffs[i] = (cCoeffs[i] + (lower << shift)) & 0x7FF7FF7FF7FF7FFL; int nextIdx = i + 1; cCoeffs[nextIdx] = (cCoeffs[nextIdx] + upper) & 0x7FF7FF7FF7FF7FFL; } } // reduce indices of cCoeffs modulo numCoeffs int shift2 = 12 * (_numCoeffs % 5); for (int cIdx = _coeffs.Length - 1; cIdx < cCoeffs.Length; cIdx++) { long iCoeff; // coefficient to shift into the [0..numCoeffs-1] range int newIdx; if (cIdx == _coeffs.Length - 1) { iCoeff = _numCoeffs == 5 ? 0 : cCoeffs[cIdx] >> shift2; newIdx = 0; } else { iCoeff = cCoeffs[cIdx]; newIdx = cIdx * 5 - _numCoeffs; } int base1 = newIdx / 5; int m = newIdx - base1 * 5; // m = newIdx % 5 long lower = iCoeff << (12 * m); long upper = iCoeff >> (12 * (5 - m)); cCoeffs[base1] = (cCoeffs[base1] + lower) & 0x7FF7FF7FF7FF7FFL; int base2 = base1 + 1; if (base2 < _coeffs.Length) { cCoeffs[base2] = (cCoeffs[base2] + upper) & 0x7FF7FF7FF7FF7FFL; } } return(new LongPolynomial5(cCoeffs, _numCoeffs)); }
/** * Multiplies the polynomial with a <code>TernaryPolynomial</code>, taking the indices mod N and the values mod 2048. */ public LongPolynomial5 Multiply(ITernaryPolynomial poly2) { long[,] prod = new long[5, (coeffs.Length + ((poly2.Size() + 4) / 5 - 1))]; // intermediate results, the subarrays are shifted by 0,...,4 coefficients // multiply ones int[] ones = poly2.GetOnes(); for (int idx = 0; idx != ones.Length; idx++) { int pIdx = ones[idx]; int cIdx = pIdx / 5; int m = pIdx - cIdx * 5; // m = pIdx % 5 for (int i = 0; i < coeffs.Length; i++) { prod[m, cIdx] = (prod[m, cIdx] + coeffs[i]) & 0x7FF7FF7FF7FF7FFL; cIdx++; } } // multiply negative ones (God Java Sucks) int[] negOnes = poly2.GetNegOnes(); for (int idx = 0; idx != negOnes.Length; idx++) { int pIdx = negOnes[idx]; int cIdx = pIdx / 5; int m = pIdx - cIdx * 5; // m = pIdx % 5 for (int i = 0; i < coeffs.Length; i++) { prod[m, cIdx] = (0x800800800800800L + prod[m, cIdx] - coeffs[i]) & 0x7FF7FF7FF7FF7FFL; cIdx++; } } // combine shifted coefficients (5 arrays) into a single array of length prod[*].Length+1 // long[] cCoeffs = Arrays.copyOf(prod[0], prod[0].length + 1); long[] cCoeffs = new long[prod.Length + 1]; prod.FlatCopyTo(cCoeffs); int pLen = prod.GetLength(1); // All polynomials must be the same size, or boom! for (int m = 1; m <= 4; m++) { int shifter = m * 12; int shift60 = 60 - shifter; long mask = (1L << shift60) - 1; for (int i = 0; i < pLen; i++) { long upper, lower; upper = prod[m, i] >> shift60; lower = prod[m, i] & mask; cCoeffs[i] = (cCoeffs[i] + (lower << shifter)) & 0x7FF7FF7FF7FF7FFL; int nextIdx = i + 1; cCoeffs[nextIdx] = (cCoeffs[nextIdx] + upper) & 0x7FF7FF7FF7FF7FFL; } } // reduce indices of cCoeffs modulo numCoeffs int shift = 12 * (numCoeffs % 5); for (int cIdx = coeffs.Length - 1; cIdx < cCoeffs.Length; cIdx++) { long iCoeff; // coefficient to shift into the [0..numCoeffs-1] range int newIdx; if (cIdx == coeffs.Length - 1) { iCoeff = numCoeffs == 5 ? 0 : cCoeffs[cIdx] >> shift; newIdx = 0; } else { iCoeff = cCoeffs[cIdx]; newIdx = cIdx * 5 - numCoeffs; } int baseCoef = newIdx / 5; int m = newIdx - baseCoef * 5; // m = newIdx % 5 long lower = iCoeff << (12 * m); long upper = iCoeff >> (12 * (5 - m)); cCoeffs[baseCoef] = (cCoeffs[baseCoef] + lower) & 0x7FF7FF7FF7FF7FFL; int base1 = baseCoef + 1; if (base1 < coeffs.Length) { cCoeffs[base1] = (cCoeffs[base1] + upper) & 0x7FF7FF7FF7FF7FFL; } } return(new LongPolynomial5(cCoeffs, numCoeffs)); }