private void TestAddModFn() { Random rng = new Random(); int n = 5 + rng.Next(10); int len = 1 << (n + 1 - 5); int[] aArr = new int[len]; for (int i = 0; i < aArr.Length; i++) { aArr[i] = rng.Next(); } BigInteger a = SchonhageStrassen.ToBigInteger(aArr); int[] bArr = new int[len]; for (int i = 0; i < bArr.Length; i++) { bArr[i] = rng.Next(); } BigInteger b = SchonhageStrassen.ToBigInteger(bArr); SchonhageStrassen.AddModFn(aArr, bArr); SchonhageStrassen.ModFn(aArr); BigInteger Fn = BigInteger.ValueOf(2).Pow(1 << n).Add(BigInteger.One); BigInteger c = a.Add(b).Mod(Fn); if (!Compare.Equals(c, SchonhageStrassen.ToBigInteger(aArr))) { throw new Exception("SchönhageStrassen:AddModFn test has failed!"); } }
private void TestToBigInteger() { Random rng = new Random(); byte[] a = new byte[1 + rng.Next(100)]; rng.NextBytes(a); int[] b = SchonhageStrassen.ToIntArray(new BigInteger(1, a)); BigInteger c = SchonhageStrassen.ToBigInteger(b); if (!Compare.Equals(new BigInteger(1, a), c)) { throw new Exception("SchönhageStrassen:ToBigInteger test has failed!"); } }
/// <summary> /// Multiplies the polynomial by another, taking the indices mod N. /// <para>Does not change this polynomial but returns the result as a new polynomial. /// Both polynomials must have the same number of coefficients. /// This method is designed for large polynomials and uses Schönhage-Strassen multiplication /// in combination with <a href="http://en.wikipedia.org/wiki/Kronecker_substitution">Kronecker substitution</a>. /// See <a href="http://math.stackexchange.com/questions/58946/karatsuba-vs-schonhage-strassen-for-multiplication-of-polynomials#58955">here</a> for details.</para> /// </summary> /// /// <param name="Factor">The polynomial to multiply by</param> /// /// <returns>The product polynomial</returns> public BigIntPolynomial MultBig(BigIntPolynomial Factor) { int N = Coeffs.Length; // determine #bits needed per coefficient int logMinDigits = 32 - IntUtils.NumberOfLeadingZeros(N - 1); int maxLengthA = 0; for (int i = 0; i < Coeffs.Length; i++) { BigInteger coeff = Coeffs[i]; maxLengthA = Math.Max(maxLengthA, coeff.BitLength); } int maxLengthB = 0; for (int i = 0; i < Factor.Coeffs.Length; i++) { BigInteger coeff = Factor.Coeffs[i]; maxLengthB = Math.Max(maxLengthB, coeff.BitLength); } int k = logMinDigits + maxLengthA + maxLengthB + 1; // in bits k = (k + 31) / 32; // in ints // encode each polynomial into an int[] int aDeg = Degree(); int bDeg = Factor.Degree(); if (aDeg < 0 || bDeg < 0) { return(new BigIntPolynomial(N)); // return zero } int[] aInt = ToIntArray(this, k); int[] bInt = ToIntArray(Factor, k); int[] cInt = SchonhageStrassen.Multiply(aInt, bInt); // decode poly coefficients from the product BigInteger _2k = BigInteger.One.ShiftLeft(k * 32); BigIntPolynomial cPoly = new BigIntPolynomial(N); for (int i = 0; i < 2 * N - 1; i++) { int[] coeffInt = cInt.CopyOfRange(i * k, (i + 1) * k); BigInteger coeff = SchonhageStrassen.ToBigInteger(coeffInt); if (coeffInt[k - 1] < 0) { // if coeff > 2^(k-1) coeff = coeff.Subtract(_2k); // add 2^k to cInt which is the same as subtracting coeff bool carry = false; int cIdx = (i + 1) * k; do { cInt[cIdx]++; carry = cInt[cIdx] == 0; cIdx++; } while (carry); } cPoly.Coeffs[i % N] = cPoly.Coeffs[i % N].Add(coeff); } int aSign = Coeffs[aDeg].Signum(); int bSign = Factor.Coeffs[bDeg].Signum(); if (aSign * bSign < 0) { for (int i = 0; i < N; i++) { cPoly.Coeffs[i] = cPoly.Coeffs[i].Negate(); } } return(cPoly); }