private void TestMult() { TestMult(BigInteger.ValueOf(0), BigInteger.ValueOf(0)); TestMult(BigInteger.ValueOf(100), BigInteger.ValueOf(100)); TestMult(BigInteger.ValueOf(-394786896548787L), BigInteger.ValueOf(604984572698687L)); TestMult(BigInteger.ValueOf(415338904376L), BigInteger.ValueOf(527401434558L)); TestMult(new BigInteger("9145524700683826415"), new BigInteger("1786442289234590209543")); BigInteger pow19_1 = BigInteger.ValueOf(1).ShiftLeft((1 << 19) - 1); // 2^(2^19-1) BigInteger pow20_2 = BigInteger.ValueOf(1).ShiftLeft((1 << 20) - 2); // 2^(2^20-2) BigInteger pow19 = BigInteger.ValueOf(1).ShiftLeft(1 << 19); // 2^2^19 BigInteger pow20 = BigInteger.ValueOf(1).ShiftLeft(1 << 20); // 2^2^20 if (!Compare.Equals(pow19_1.ShiftLeft(1024).Subtract(pow19_1), SchonhageStrassen.Multiply(pow19_1, BigInteger.ValueOf(1).ShiftLeft(1024).Subtract(BigInteger.One)))) { throw new Exception("SchönhageStrassen:TestMult test has failed!"); } if (!Compare.Equals(pow20_2, SchonhageStrassen.Multiply(pow19_1, pow19_1))) { throw new Exception("SchönhageStrassen:TestMult test has failed!"); } if (!Compare.Equals(pow20_2.Subtract(pow19_1), SchonhageStrassen.Multiply(pow19_1, pow19_1.Subtract(BigInteger.One)))) { throw new Exception("SchönhageStrassen:TestMult test has failed!"); } if (!Compare.Equals(pow20_2.Add(pow19_1), SchonhageStrassen.Multiply(pow19_1, pow19_1.Add(BigInteger.One)))) { throw new Exception("SchönhageStrassen:TestMult test has failed!"); } if (!Compare.Equals(pow20, SchonhageStrassen.Multiply(pow19, pow19))) { throw new Exception("SchönhageStrassen:TestMult test has failed!"); } if (!Compare.Equals(pow20.Subtract(pow19), SchonhageStrassen.Multiply(pow19, pow19.Subtract(BigInteger.One)))) { throw new Exception("SchönhageStrassen:TestMult test has failed!"); } if (!Compare.Equals(pow20.Add(pow19), SchonhageStrassen.Multiply(pow19, pow19.Add(BigInteger.One)))) { throw new Exception("SchönhageStrassen:TestMult test has failed!"); } OnProgress(new TestEventArgs("Passed Known Value Multiplication test")); Random rng = new Random(); TestMult(BigInteger.ValueOf(rng.Next(1000000000) + 524288), BigInteger.ValueOf(rng.Next(1000000000) + 524288)); TestMult(BigInteger.ValueOf((rng.Next() >> 1) + 1000), BigInteger.ValueOf((rng.Next() >> 1) + 1000)); TestMult(BigInteger.ValueOf(rng.Next(1000000000) + 524288), BigInteger.ValueOf(rng.Next(1000000000) + 524288)); TestMult(BigInteger.ValueOf((rng.Next() >> 1) + 1000), BigInteger.ValueOf((rng.Next() >> 1) + 1000)); OnProgress(new TestEventArgs("Passed Random Multiplication test")); int aLength = 80000 + rng.Next(20000); int bLength = 80000 + rng.Next(20000); for (int i = 0; i < 2; i++) { byte[] aArr = new byte[aLength]; rng.NextBytes(aArr); byte[] bArr = new byte[bLength]; rng.NextBytes(bArr); BigInteger a = new BigInteger(aArr); BigInteger b = new BigInteger(bArr); TestMult(a, b); // double the length and test again so an even and an odd m is tested aLength *= 2; bLength *= 2; } OnProgress(new TestEventArgs("Passed Large Number Multiplication test")); }
/// <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); }
private void TestMult(BigInteger a, BigInteger b) { Compare.Equals(a.Multiply(b), SchonhageStrassen.Multiply(a, b)); }