Ejemplo n.º 1
0
        /// <summary>
        /// Schoolbook division helper function.
        /// </summary>
        /// <param name="n1"></param>
        /// <param name="n2"></param>
        /// <param name="Q">Quotient output value</param>
        /// <param name="R">Remainder output value</param>
        private static void Div_31(BigInt n1, BigInt n2, BigInt Q, BigInt R)
        {
            int digitsN1 = n1.GetMSD() + 1;
            int digitsN2 = n2.GetMSD() + 1;            

            if ((digitsN1 > digitsN2))
            {
                BigInt n1New = new BigInt(n2);
                n1New.DigitShiftSelfLeft(1);

                //If n1 >= n2 * 2^32
                if (!LtInt(n1, n1New))
                {
                    n1New.sign = n1.sign;
                    SubFast(n1New, n1, n1New);

                    Div_32(n1New, n2, Q, R);

                    //Q = (A - B*2^32)/B + 2^32
                    Q.Add2Pow32Self();
                    return;
                }
            }

            UInt32 q = 0;

            if (digitsN1 >= 2)
            {
                UInt64 q64 = ((((UInt64)n1.digitArray[digitsN1 - 1]) << 32) + n1.digitArray[digitsN1 - 2]) / (UInt64)n2.digitArray[digitsN2 - 1];

                if (q64 > 0xfffffffful)
                {
                    q = 0xffffffff;
                }
                else
                {
                    q = (UInt32)q64;
                }
            }

            BigInt temp = Mul(n2, q);

            if (GtInt(temp, n1))
            {
                temp.SubInternalBits(n2.digitArray);
                q--;

                if (GtInt(temp, n1))
                {
                    temp.SubInternalBits(n2.digitArray);
                    q--;
                }
            }

            Q.Zero();
            Q.digitArray[0] = q;
            R.Assign(n1);
            R.SubInternalBits(temp.digitArray);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Schoolbook division algorithm
        /// </summary>
        /// <param name="n1"></param>
        /// <param name="n2"></param>
        /// <param name="Q"></param>
        /// <param name="R"></param>
        private static void Div_32(BigInt n1, BigInt n2, BigInt Q, BigInt R)
        {
            int digitsN1 = n1.GetMSD() + 1;
            int digitsN2 = n2.GetMSD() + 1;

            //n2 is bigger than n1
            if (digitsN1 < digitsN2)
            {
                R.AssignInt(n1);
                Q.Zero();
                return;
            }

            if (digitsN1 == digitsN2)
            {
                //n2 is bigger than n1
                if (LtInt(n1, n2))
                {
                    R.AssignInt(n1);
                    Q.Zero();
                    return;
                }

                //n2 >= n1, but less the 2x n1 (initial conditions make this certain)
                Q.Zero();
                Q.digitArray[0] = 1;
                R.Assign(n1);
                R.SubInternalBits(n2.digitArray);
                return;
            }

            int digits = digitsN1 - (digitsN2 + 1);

            //Algorithm Div_31 can be used to get the answer in O(n) time.
            if (digits == 0)
            {
                Div_31(n1, n2, Q, R);
                return;
            }

            BigInt n1New = DigitShiftRight(n1, digits);
            BigInt s = DigitTruncate(n1, digits);

            BigInt Q2 = new BigInt(n1, n1.pres, true);
            BigInt R2 = new BigInt(n1, n1.pres, true);

            Div_31(n1New, n2, Q2, R2);

            R2.DigitShiftSelfLeft(digits);
            R2.Add(s);

            Div_32(R2, n2, Q, R);

            Q2.DigitShiftSelfLeft(digits);
            Q.Add(Q2);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Adds n1 and n2 and puts result in dest, without intermediate memory allocation
        /// (unsafe if n1 and n2 disagree in precision, safe even if dest is n1 or n2)
        /// </summary>
        /// <param name="dest"></param>
        /// <param name="n1"></param>
        /// <param name="n2"></param>
        public static void SubFast(BigInt dest, BigInt n1, BigInt n2)
        {
            //We cast to the highest input precision...
            if (n1.digitArray.Length != n2.digitArray.Length) MakeSafe(ref n1, ref n2);

            //Then we up the output precision if less than the input precision.
            if (dest.digitArray.Length < n1.digitArray.Length) n1.MakeSafe(ref dest);

            int Length = n1.digitArray.Length;

            if (n1.sign != n2.sign)
            {
                //Copies sources into digit array and working set for all cases, to avoid
                //problems when dest is n1 or n2
                for (int i = 0; i < Length; i++)
                {
                    dest.workingSet[i] = n2.digitArray[i];
                    dest.digitArray[i] = n1.digitArray[i];
                }
                dest.AddInternalBits(dest.workingSet);
                dest.sign = n1.sign;
            }
            else
            {
                bool lessThan = LtInt(n1, n2);

                if (lessThan)
                {
                    for (int i = 0; i < Length; i++)
                    {
                        dest.workingSet[i] = n1.digitArray[i];
                        dest.digitArray[i] = n2.digitArray[i];
                    }
                    dest.SubInternalBits(dest.workingSet);
                    dest.sign = !n1.sign;
                }
                else
                {
                    for (int i = 0; i < Length; i++)
                    {
                        dest.workingSet[i] = n2.digitArray[i];
                        dest.digitArray[i] = n1.digitArray[i];
                    }
                    dest.SubInternalBits(dest.workingSet);
                    dest.sign = n1.sign;
                }
            }
        }