예제 #1
0
        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"));
        }
예제 #2
0
        /// <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);
        }
예제 #3
0
 private void TestMult(BigInteger a, BigInteger b)
 {
     Compare.Equals(a.Multiply(b), SchonhageStrassen.Multiply(a, b));
 }