Пример #1
0
        /// <summary>
        /// Calculates 'this' mod n2 (using the schoolbook division algorithm as above)
        /// </summary>
        /// <param name="n2"></param>
        public void Mod(BigInt n2)
        {
            if (n2.digitArray.Length != digitArray.Length) MakeSafe(ref n2);

            int OldLength = digitArray.Length;

            //First, we need to prepare the operands for division using Div_32, which requires
            //That the most significant digit of n2 be set. To do this, we need to shift n2 (and therefore n1) up.
            //This operation can potentially increase the precision of the operands.
            int shift = MakeSafeDiv(this, n2);

            BigInt Q = new BigInt(this.pres);
            BigInt R = new BigInt(this.pres);

            Q.digitArray = new UInt32[this.digitArray.Length];
            R.digitArray = new UInt32[this.digitArray.Length];

            Div_32(this, n2, Q, R);

            //Restore n2 to its pre-shift value
            n2.RSH(shift);
            R.RSH(shift);
            R.sign = (sign != n2.sign);
            AssignInt(R);

            //Reset the lengths of the operands
            SetNumDigits(OldLength);
            n2.SetNumDigits(OldLength);
        }
Пример #2
0
 /// <summary>
 /// Makes sure the numbers have matching precisions
 /// </summary>
 /// <param name="n2">the number to match to this</param>
 private void MakeSafe(ref BigInt n2)
 {
     n2 = new BigInt(n2, pres);
     n2.SetNumDigits(digitArray.Length);
 }
Пример #3
0
        /// <summary>
        /// This function is used for floating-point division.
        /// </summary>
        /// <param name="n2"></param>
        //Given two numbers:
        //  In floating point 1 <= a, b < 2, meaning that both numbers have their top bits set.
        //  To calculate a / b, maintaining precision, we:
        //    1. Double the number of digits available to both numbers.
        //    2. set a = a * 2^d (where d is the number of digits)
        //    3. calculate the quotient a <- q:  2^(d-1) <= q < 2^(d+1)
        //    4. if a >= 2^d, s = 1, else s = 0
        //    6. shift a down by s, and undo the precision extension
        //    7. return 1 - shift (change necessary to exponent)
        public int DivAndShift(BigInt n2)
        {
            if (n2.IsZero()) return -1;
            if (digitArray.Length != n2.digitArray.Length) MakeSafe(ref n2);

            int oldLength = digitArray.Length;

            //Double the number of digits, and shift a into the higher digits.
            Pad();
            n2.Extend();

            //Do the divide (at double precision, ouch!)
            Div(n2);

            //Shift down if 'this' >= 2^d
            int ret = 1;

            if (digitArray[oldLength] != 0)
            {
                RSH(1);
                ret--;
            }

            SetNumDigits(oldLength);
            n2.SetNumDigits(oldLength);

            return ret;
        }
Пример #4
0
        /// <summary>
        /// Shifts and optionally precision-extends the arguments to prepare for Div_32
        /// </summary>
        /// <param name="n1"></param>
        /// <param name="n2"></param>
        private static int MakeSafeDiv(BigInt n1, BigInt n2)
        {
            int shift = n2.GetDivBitshift();
            int n1MSD = n1.GetMSD();

            uint temp = n1.digitArray[n1MSD];
            if (n1MSD == n1.digitArray.Length - 1 && ((temp << shift) >> shift) != n1.digitArray[n1MSD])
            {
                //Precision-extend n1 and n2 if necessary
                int digits = n1.digitArray.Length;
                n1.SetNumDigits(digits + 1);
                n2.SetNumDigits(digits + 1);
            }

            //Logical left-shift n1 and n2
            n1.LSH(shift);
            n2.LSH(shift);

            return shift;
        }