Пример #1
0
 /// <summary>
 /// Bitwise Xor
 /// </summary>
 /// <param name="n1"></param>
 /// <param name="n2"></param>
 /// <returns></returns>
 public static BigInt Xor(BigInt n1, BigInt n2)
 {
     if (n1.digitArray.Length != n2.digitArray.Length) MakeSafe(ref n1, ref n2);
     BigInt res = new BigInt(n1);
     res.And(n2);
     return res;
 }
Пример #2
0
        /// <summary>
        /// Floating-point helper function.
        /// Squares the number and keeps the high bits of the calculation.
        /// Takes a temporary BigInt as a working set.
        /// </summary>
        public void SquareHiFast(BigInt scratch)
        {
            int Length = digitArray.Length;
            uint[] tempDigits = scratch.digitArray;
            uint[] workingSet2 = scratch.workingSet;

            //Temp storage for source (both working sets are used by the calculation)
            for (int i = 0; i < Length; i++)
            {
                tempDigits[i] = digitArray[i];
                digitArray[i] = 0;
            }

            for (int i = 0; i < Length; i++)
            {
                //Clear the working set
                for (int j = i; j < Length; j++)
                {
                    workingSet[j] = 0;
                    workingSet2[j] = 0;
                }

                if (i - 1 >= 0) workingSet[i - 1] = 0;

                ulong digit = tempDigits[i];
                if (digit == 0) continue;

                for (int j = 0; j < Length; j++)
                {
                    if (j + i + 1 < Length) continue;
                    //Multiply n1 by each of the integer digits of n2.
                    ulong temp = (ulong)tempDigits[j] * digit;
                    //n1.workingSet stores the low bits of each piecewise multiplication
                    if (j + i >= Length)
                    {
                        workingSet[j + i - Length] = (uint)(temp & 0xffffffff);
                    }

                    //n2.workingSet stores the high bits of each multiplication
                    workingSet2[j + i + 1 - Length] = (uint)(temp >> 32);
                }

                AddInternalBits(workingSet);
                AddInternalBits(workingSet2);
            }

            sign = false;
        }
Пример #3
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);
        }
Пример #4
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);
 }
Пример #5
0
        /// <summary>
        /// Subtraction and assignment - without intermediate memory allocation.
        /// </summary>
        /// <param name="n2"></param>
        public uint Sub(BigInt n2)
        {
            if (n2.digitArray.Length != digitArray.Length) MakeSafe(ref n2);

            if (sign != n2.sign)
            {
                return AddInternalBits(n2.digitArray);
            }
            else
            {
                bool lessThan = LtInt(this, n2);

                if (lessThan)
                {
                    int Length = digitArray.Length;

                    for (int i = 0; i < Length; i++)
                    {
                        workingSet[i] = digitArray[i];
                        digitArray[i] = n2.digitArray[i];
                    }

                    sign = !sign;
                    return SubInternalBits(workingSet);
                }
                else
                {
                    return SubInternalBits(n2.digitArray);
                }
            }
        }
Пример #6
0
        private string BuildString(BigInt n, int m)
        {
            if (m == 0)
                return n.ToString(10);

            BigInt remainder;
            BigInt quotient = BigInt.DivRem(n, powersOfTen[m], out remainder);

            return BuildString(quotient, m - 1) + BuildString(remainder, m - 1);
        }
Пример #7
0
        /// <summary>
        /// Sign-insensitive greater than comparison. 
        /// unsafe if n1 and n2 disagree in precision
        /// </summary>
        /// <param name="n1"></param>
        /// <param name="n2"></param>
        /// <returns></returns>
        private static bool GtInt(BigInt n1, BigInt n2)
        {
            //MakeSafe(ref n1, ref n2);

            for (int i = n1.digitArray.Length - 1; i >= 0; i--)
            {
                if (n1.digitArray[i] > n2.digitArray[i]) return true;
                if (n1.digitArray[i] < n2.digitArray[i]) return false;
            }

            //equal
            return false;
        }
Пример #8
0
 /// <summary>
 /// Gets the most significant bit
 /// </summary>
 /// <param name="value">the input to search for the MSB in</param>
 /// <returns>-1 if the input was zero, the position of the MSB otherwise</returns>
 public static int GetMSB(BigInt value)
 {
     int digit = value.GetMSD();
     int bit = GetMSB(value.digitArray[digit]);
     return (digit << 5) + bit;
 }
Пример #9
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;
        }
Пример #10
0
        /// <summary>
        /// Used for casting between BigFloats of different precisions - this assumes
        /// that the number is a normalised mantissa.
        /// </summary>
        /// <param name="n2"></param>
        /// <returns>true if a round-up caused the high bits to become zero</returns>
        public bool AssignHigh(BigInt n2)
        {
            int length = digitArray.Length;
            int length2 = n2.digitArray.Length;
            int minWords = (length < length2) ? length : length2;
            bool bRet = false;

            for (int i = 1; i <= minWords; i++)
            {
                digitArray[length - i] = n2.digitArray[length2 - i];
            }

            if (length2 > length && n2.digitArray[length2 - (length + 1)] >= 0x80000000)
            {
                bRet = IncrementInt();

                //Because we are assuming normalisation, we set the top bit (it will already be set if
                //bRet is false.
                digitArray[length - 1] = digitArray[length - 1] | 0x80000000;
            }

            sign = n2.sign;

            return bRet;
        }
Пример #11
0
 /// <summary>
 /// Constructor for copying length and precision
 /// </summary>
 /// <param name="inputToCopy">The BigInt to copy</param>
 /// <param name="precision">The precision of the new BigInt</param>
 /// <param name="bCopyLengthOnly">decides whether to copy the actual input, or just its digit length</param>
 /// <example><code>//Create an integer
 /// BigInt four = new BigInt(4, new PrecisionSpec(128, PrecisionSpec.BaseType.BIN));
 /// 
 /// //Pad four to double its usual number of digits (this does not affect the precision)
 /// four.Pad();
 /// 
 /// //Create a new, empty integer with matching precision, also padded to twice the usual length
 /// BigInt newCopy = new BigInt(four, four.Precision, true);</code></example>
 public BigInt(BigInt inputToCopy, PrecisionSpec precision, bool bCopyLengthOnly)
 {
     digitArray = new uint[inputToCopy.digitArray.Length];
     workingSet = new uint[inputToCopy.digitArray.Length];
     if (!bCopyLengthOnly) Array.Copy(inputToCopy.digitArray, digitArray, digitArray.Length);
     sign = inputToCopy.sign;
     pres = inputToCopy.pres;
 }
Пример #12
0
 /// <summary>
 /// Used to subtract n1 (true subtraction of digit arrays) - n1 must be less than or equal to this number
 /// </summary>
 /// <param name="n1"></param>
 private uint SubInternal(BigInt n1)
 {
     return SubInternalBits(n1.digitArray);
 }
Пример #13
0
 /// <summary>
 /// Used to add with matching signs (true addition of the digit arrays)
 /// This is internal because it will fail spectacularly if n1 is negative.
 /// </summary>
 /// <param name="n1"></param>
 private uint AddInternal(BigInt n1)
 {
     return AddInternalBits(n1.digitArray);
 }
Пример #14
0
 /// <summary>
 /// The right-shift operator
 /// </summary>
 public static BigInt operator >>(BigInt n1, int n2)
 {
     BigInt res = new BigInt(n1);
     res.RSH(n2);
     return res;
 }
Пример #15
0
        /// <summary>
        /// Constructs a bigint from the input, matching the new precision provided
        /// </summary>
        public BigInt(BigInt input, PrecisionSpec precision)
        {
            //Casts the input to the new precision.
            Init(precision);
            int Min = (input.digitArray.Length < digitArray.Length) ? input.digitArray.Length : digitArray.Length;

            for (int i = 0; i < Min; i++)
            {
                digitArray[i] = input.digitArray[i];
            }

            sign = input.sign;
        }
Пример #16
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);
        }
Пример #17
0
        //********************* ToString members **********************
        public String ToQuickString()
        {
            powersOfTen = new List<BigInt>();
            powersOfTen.Add(new BigInt((int)1, new PrecisionSpec(1, PrecisionSpec.BaseType.DEC)));

            for (BigInt i = new BigInt((int)10, new PrecisionSpec(1, PrecisionSpec.BaseType.DEC)); i.LessThan(this); i *= i)
            {
                powersOfTen.Add(i);
            }

            return BuildString(this, powersOfTen.Count - 1).TrimStart('0');
        }
Пример #18
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);
        }
Пример #19
0
        /// <summary>
        /// Converts this to a string, in the specified base
        /// </summary>
        /// <param name="numberBase">the base to use (min 2, max 16)</param>
        /// <returns>a string representation of the number</returns>
        public string ToString(int numberBase)
        {
            char[] digitChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

            string output = "";

            BigInt clone = new BigInt(this);
            clone.sign = false;

            int numDigits = 0;
            while (!clone.IsZero())
            {
                BigInt div, mod;
                DivMod(clone, (uint)numberBase, out div, out mod);
                int iMod = (int)mod;
                output = String.Concat(digitChars[(int)mod], output);

                numDigits++;

                clone = div;
            }

            if (output.Length == 0) output = "0";

            if (sign) output = String.Concat("-", output);

            return output;
        }
Пример #20
0
 /// <summary>
 /// Assigns n2 to 'this'
 /// </summary>
 /// <param name="n2"></param>
 public void Assign(BigInt n2)
 {
     if (digitArray.Length != n2.digitArray.Length) MakeSafe(ref n2);
     sign = n2.sign;
     AssignInt(n2);
 }
Пример #21
0
 /// <summary>
 /// Makes sure the numbers have matching precisions
 /// </summary>
 /// <param name="n1"></param>
 /// <param name="n2"></param>
 private static void MakeSafe(ref BigInt n1, ref BigInt n2)
 {
     if (n1.digitArray.Length == n2.digitArray.Length)
     {
         return;
     }
     else if (n1.digitArray.Length > n2.digitArray.Length)
     {
         n2 = new BigInt(n2, n1.pres);
     }
     else
     {
         n1 = new BigInt(n1, n2.pres);
     }
 }
Пример #22
0
        /// <summary>
        /// Assign n2 to 'this', safe only if precision-matched
        /// </summary>
        /// <param name="n2"></param>
        /// <returns></returns>
        private void AssignInt(BigInt n2)
        {
            int Length = digitArray.Length;

            for (int i = 0; i < Length; i++)
            {
                digitArray[i] = n2.digitArray[i];
            }
        }
Пример #23
0
        //*************** Utility Functions **************

        /// <summary>
        /// Casts a BigInt to the new precision provided.
        /// Note: This will return the input if the precision already matches.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="precision"></param>
        /// <returns></returns>
        public static BigInt CastToPrecision(BigInt input, PrecisionSpec precision)
        {
            if (input.pres == precision) return input;
            return new BigInt(input, precision);
        }
Пример #24
0
        private static BigInt DigitShiftRight(BigInt n1, int digits)
        {
            BigInt res = new BigInt(n1);

            int Length = res.digitArray.Length;

            for (int i = 0; i < Length - digits; i++)
            {
                res.digitArray[i] = res.digitArray[i + digits];
            }

            for (int i = Length - digits; i < Length; i++)
            {
                res.digitArray[i] = 0;
            }

            return res;
        }
Пример #25
0
        /// <summary>
        /// Used for floating-point multiplication
        /// Stores the high bits of the multiplication only (the carry bit from the
        /// lower bits is missing, so the true answer might be 1 greater).
        /// </summary>
        /// <param name="n2"></param>
        public void MulHi(BigInt n2)
        {
            if (n2.digitArray.Length != digitArray.Length) MakeSafe(ref n2);

            int Length = n2.digitArray.Length;

            //Inner loop zero-mul avoidance
            int maxDigit = 0;
            for (int i = Length - 1; i >= 0; i--)
            {
                if (digitArray[i] != 0)
                {
                    maxDigit = i + 1;
                    break;
                }
            }

            //Result is zero, 'this' is unchanged
            if (maxDigit == 0) return;

            //Temp storage for source (both working sets are used by the calculation)
            uint[] thisTemp = new uint[Length];
            for (int i = 0; i < Length; i++)
            {
                thisTemp[i] = digitArray[i];
                digitArray[i] = 0;
            }

            for (int i = 0; i < Length; i++)
            {
                //Clear the working set
                for (int j = 0; j < Length; j++)
                {
                    workingSet[j] = 0;
                    n2.workingSet[j] = 0;
                }

                n2.workingSet[i] = 0;

                ulong digit = n2.digitArray[i];
                if (digit == 0) continue;

                //Only the high bits
                if (maxDigit + i < Length - 1) continue;

                for (int j = 0; j < maxDigit; j++)
                {
                    if (j + i + 1 < Length) continue;
                    //Multiply n1 by each of the integer digits of n2.
                    ulong temp = (ulong)thisTemp[j] * digit;
                    //n1.workingSet stores the low bits of each piecewise multiplication
                    if (j + i >= Length)
                    {
                        workingSet[j + i - Length] = (uint)(temp & 0xffffffff);
                    }

                    //n2.workingSet stores the high bits of each multiplication
                    n2.workingSet[j + i + 1 - Length] = (uint)(temp >> 32);
                }

                AddInternalBits(workingSet);
                AddInternalBits(n2.workingSet);
            }

            sign = (sign != n2.sign);
        }
Пример #26
0
 /// <summary>
 /// Constructs a bigint from the input.
 /// </summary>
 /// <param name="input"></param>
 public BigInt(BigInt input)
 {
     digitArray = new uint[input.digitArray.Length];
     workingSet = new uint[input.digitArray.Length];
     Array.Copy(input.digitArray, digitArray, digitArray.Length);
     sign = input.sign;
     pres = input.pres;
 }
Пример #27
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;
        }
Пример #28
0
        private static BigInt DigitTruncate(BigInt n1, int digits)
        {
            BigInt res = new BigInt(n1);

            for (int i = res.digitArray.Length - 1; i >= digits; i--)
            {
                res.digitArray[i] = 0;
            }

            return res;
        }
Пример #29
0
        /// <summary>
        /// Calculates 'this'^power
        /// </summary>
        /// <param name="power"></param>
        public void Power(BigInt power)
        {
            if (power.IsZero() || power.sign)
            {
                Zero();
                digitArray[0] = 1;
                return;
            }

            BigInt pow = new BigInt(power);
            BigInt temp = new BigInt(this);
            BigInt powTerm = new BigInt(this);

            pow.Decrement();
            for (; !pow.IsZero(); pow.RSH(1))
            {
                if ((pow.digitArray[0] & 1) == 1)
                {
                    temp.Mul(powTerm);
                }

                powTerm.Square();
            }

            Assign(temp);
        }
Пример #30
0
 /// <summary>
 /// true iff n1 == n2
 /// </summary>
 /// <param name="n1"></param>
 /// <param name="n2"></param>
 /// <returns></returns>
 public static bool Equals(BigInt n1, BigInt n2)
 {
     return n1.Equals(n2);
 }