Beispiel #1
0
        private static void SingleDivide(BigInteger leftSide, BigInteger rightSide, out BigInteger quotient, out BigInteger remainder)
        {
            if (rightSide.IsZero)
            {
                throw new DivideByZeroException();
            }

            DigitsArray remainderDigits = new DigitsArray(leftSide.m_digits);
            remainderDigits.ResetDataUsed();

            int pos = remainderDigits.DataUsed - 1;
            ulong divisor = (ulong)rightSide.m_digits[0];
            ulong dividend = (ulong)remainderDigits[pos];

            DType[] result = new DType[leftSide.m_digits.Count];
            leftSide.m_digits.CopyTo(result, 0, result.Length);
            int resultPos = 0;

            if (dividend >= divisor)
            {
                result[resultPos++] = (DType)(dividend / divisor);
                remainderDigits[pos] = (DType)(dividend % divisor);
            }
            pos--;

            while (pos >= 0)
            {
                dividend = ((ulong)(remainderDigits[pos + 1]) << DigitsArray.DataSizeBits) + (ulong)remainderDigits[pos];
                result[resultPos++] = (DType)(dividend / divisor);
                remainderDigits[pos + 1] = 0;
                remainderDigits[pos--] = (DType)(dividend % divisor);
            }
            remainder = new BigInteger(remainderDigits);

            DigitsArray quotientDigits = new DigitsArray(resultPos + 1, resultPos);
            int j = 0;
            for (int i = quotientDigits.DataUsed - 1; i >= 0; i--, j++)
            {
                quotientDigits[j] = result[i];
            }
            quotient = new BigInteger(quotientDigits);
        }
Beispiel #2
0
        /// <summary>
        /// Multiply two BigIntegers returning the result.
        /// </summary>
        /// <remarks>
        /// See Knuth.
        /// </remarks>
        /// <param name="leftSide">A BigInteger.</param>
        /// <param name="rightSide">A BigInteger</param>
        /// <returns></returns>
        public static BigInteger operator *(BigInteger leftSide, BigInteger rightSide)
        {
            if (object.ReferenceEquals(leftSide, null))
            {
                throw new ArgumentNullException("leftSide");
            }
            if (object.ReferenceEquals(rightSide, null))
            {
                throw new ArgumentNullException("rightSide");
            }

            bool leftSideNeg = leftSide.IsNegative;
            bool rightSideNeg = rightSide.IsNegative;

            leftSide = Abs(leftSide);
            rightSide = Abs(rightSide);

            DigitsArray da = new DigitsArray(leftSide.m_digits.DataUsed + rightSide.m_digits.DataUsed);
            da.DataUsed = da.Count;

            for (int i = 0; i < leftSide.m_digits.DataUsed; i++)
            {
                ulong carry = 0;
                for (int j = 0, k = i; j < rightSide.m_digits.DataUsed; j++, k++)
                {
                    ulong val = ((ulong)leftSide.m_digits[i] * (ulong)rightSide.m_digits[j]) + (ulong)da[k] + carry;

                    da[k] = (DType)(val & DigitsArray.AllBits);
                    carry = (val >> DigitsArray.DataSizeBits);
                }

                if (carry != 0)
                {
                    da[i + rightSide.m_digits.DataUsed] = (DType)carry;
                }
            }

            //da.ResetDataUsed();
            BigInteger result = new BigInteger(da);
            return (leftSideNeg != rightSideNeg ? -result : result);
        }
Beispiel #3
0
        private static void MultiDivide(BigInteger leftSide, BigInteger rightSide, out BigInteger quotient, out BigInteger remainder)
        {
            if (rightSide.IsZero)
            {
                throw new DivideByZeroException();
            }

            DType val = rightSide.m_digits[rightSide.m_digits.DataUsed - 1];
            int d = 0;
            for (uint mask = DigitsArray.HiBitSet; mask != 0 && (val & mask) == 0; mask >>= 1)
            {
                d++;
            }

            int remainderLen = leftSide.m_digits.DataUsed + 1;
            DType[] remainderDat = new DType[remainderLen];
            leftSide.m_digits.CopyTo(remainderDat, 0, leftSide.m_digits.DataUsed);

            DigitsArray.ShiftLeft(remainderDat, d);
            rightSide = rightSide << d;

            ulong firstDivisor = rightSide.m_digits[rightSide.m_digits.DataUsed - 1];
            ulong secondDivisor = (rightSide.m_digits.DataUsed < 2 ? (DType)0 : rightSide.m_digits[rightSide.m_digits.DataUsed - 2]);

            int divisorLen = rightSide.m_digits.DataUsed + 1;
            DigitsArray dividendPart = new DigitsArray(divisorLen, divisorLen);
            DType[] result = new DType[leftSide.m_digits.Count + 1];
            int resultPos = 0;

            ulong carryBit = (ulong)0x1 << DigitsArray.DataSizeBits; // 0x100000000
            for (int j = remainderLen - rightSide.m_digits.DataUsed, pos = remainderLen - 1; j > 0; j--, pos--)
            {
                ulong dividend = ((ulong)remainderDat[pos] << DigitsArray.DataSizeBits) + (ulong)remainderDat[pos - 1];
                ulong qHat = (dividend / firstDivisor);
                ulong rHat = (dividend % firstDivisor);

                while (pos >= 2)
                {
                    if (qHat == carryBit || (qHat * secondDivisor) > ((rHat << DigitsArray.DataSizeBits) + remainderDat[pos - 2]))
                    {
                        qHat--;
                        rHat += firstDivisor;
                        if (rHat < carryBit)
                        {
                            continue;
                        }
                    }
                    break;
                }

                for (int h = 0; h < divisorLen; h++)
                {
                    dividendPart[divisorLen - h - 1] = remainderDat[pos - h];
                }

                BigInteger dTemp = new BigInteger(dividendPart);
                BigInteger rTemp = rightSide * (long)qHat;
                while (rTemp > dTemp)
                {
                    qHat--;
                    rTemp -= rightSide;
                }

                rTemp = dTemp - rTemp;
                for (int h = 0; h < divisorLen; h++)
                {
                    remainderDat[pos - h] = rTemp.m_digits[rightSide.m_digits.DataUsed - h];
                }

                result[resultPos++] = (DType)qHat;
            }

            Array.Reverse(result, 0, resultPos);
            quotient = new BigInteger(new DigitsArray(result));

            int n = DigitsArray.ShiftRight(remainderDat, d);
            DigitsArray rDA = new DigitsArray(n, n);
            rDA.CopyFrom(remainderDat, 0, 0, rDA.DataUsed);
            remainder = new BigInteger(rDA);
        }
Beispiel #4
0
        /// <summary>
        /// Substracts two BigIntegers and returns a new BigInteger that represents the sum.
        /// </summary>
        /// <param name="leftSide">A BigInteger</param>
        /// <param name="rightSide">A BigInteger</param>
        /// <returns>The BigInteger result of substracting <paramref name="leftSide" /> and <paramref name="rightSide" />.</returns>
        public static BigInteger operator -(BigInteger leftSide, BigInteger rightSide)
        {
            int size = System.Math.Max(leftSide.m_digits.DataUsed, rightSide.m_digits.DataUsed) + 1;
            DigitsArray da = new DigitsArray(size);

            long carry = 0;
            for (int i = 0; i < da.Count; i++)
            {
                long diff = (long)leftSide.m_digits[i] - (long)rightSide.m_digits[i] - carry;
                da[i] = (DType)(diff & DigitsArray.AllBits);
                da.DataUsed++;
                carry = ((diff < 0) ? 1 : 0);
            }
            return new BigInteger(da);
        }
Beispiel #5
0
        /// <summary>
        /// Negates the BigInteger, that is, if the BigInteger is negative return a positive BigInteger, and if the
        /// BigInteger is negative return the postive.
        /// </summary>
        /// <param name="leftSide">A BigInteger operand.</param>
        /// <returns>The value of the <paramref name="this" /> negated.</returns>
        public static BigInteger operator -(BigInteger leftSide)
        {
            if (object.ReferenceEquals(leftSide, null))
            {
                throw new ArgumentNullException("leftSide");
            }

            if (leftSide.IsZero)
            {
                return new BigInteger(0);
            }

            DigitsArray da = new DigitsArray(leftSide.m_digits.DataUsed + 1, leftSide.m_digits.DataUsed + 1);

            for (int i = 0; i < da.Count; i++)
            {
                da[i] = (DType)(~(leftSide.m_digits[i]));
            }

            // add one to result (1's complement + 1)
            bool carry = true;
            int index = 0;
            while (carry && index < da.Count)
            {
                long val = (long)da[index] + 1;
                da[index] = (DType)(val & DigitsArray.AllBits);
                carry = ((val >> DigitsArray.DataSizeBits) > 0);
                index++;
            }

            return new BigInteger(da);
        }
Beispiel #6
0
 /// <summary>
 /// Copy constructor, doesn't copy the digits parameter, assumes <code>this</code> owns the DigitsArray.
 /// </summary>
 /// <remarks>The <paramef name="digits" /> parameter is saved and reset.</remarks>
 /// <param name="digits"></param>
 private BigInteger(DigitsArray digits)
 {
     digits.ResetDataUsed();
     this.m_digits = digits;
 }
Beispiel #7
0
        /// <summary>
        /// Adds two BigIntegers and returns a new BigInteger that represents the sum.
        /// </summary>
        /// <param name="leftSide">A BigInteger</param>
        /// <param name="rightSide">A BigInteger</param>
        /// <returns>The BigInteger result of adding <paramref name="leftSide" /> and <paramref name="rightSide" />.</returns>
        public static BigInteger operator +(BigInteger leftSide, BigInteger rightSide)
        {
            int size = System.Math.Max(leftSide.m_digits.DataUsed, rightSide.m_digits.DataUsed);
            DigitsArray da = new DigitsArray(size + 1);

            long carry = 0;
            for (int i = 0; i < da.Count; i++)
            {
                long sum = (long)leftSide.m_digits[i] + (long)rightSide.m_digits[i] + carry;
                carry = (long)(sum >> DigitsArray.DataSizeBits);
                da[i] = (DType)(sum & DigitsArray.AllBits);
            }

            return new BigInteger(da);
        }
Beispiel #8
0
        private void ConstructFrom(byte[] array, int offset, int length)
        {
            if (array == null)
            {
                throw new ArgumentNullException("array");
            }
            if (offset > array.Length || length > array.Length)
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if (length > array.Length || (offset + length) > array.Length)
            {
                throw new ArgumentOutOfRangeException("length");
            }

            int estSize = length / 4;
            int leftOver = length & 3;
            if (leftOver != 0)
            {
                ++estSize;
            }

            m_digits = new DigitsArray(estSize + 1, 0); // alloc one extra since we can't init -'s from here.

            for (int i = offset + length - 1, j = 0; (i - offset) >= 3; i -= 4, j++)
            {
                m_digits[j] = (DType)((array[i - 3] << 24) + (array[i - 2] << 16) + (array[i - 1] << 8) + array[i]);
                m_digits.DataUsed++;
            }

            DType accumulator = 0;
            for (int i = leftOver; i > 0; i--)
            {
                DType digit = array[offset + leftOver - i];
                digit = (digit << ((i - 1) * 8));
                accumulator |= digit;
            }
            m_digits[m_digits.DataUsed] = accumulator;

            m_digits.ResetDataUsed();
        }
Beispiel #9
0
        private void Construct(string digits, int radix)
        {
            if (digits == null)
            {
                throw new ArgumentNullException("digits");
            }

            BigInteger multiplier = new BigInteger(1);
            BigInteger result = new BigInteger();
            digits = digits.ToUpper(System.Globalization.CultureInfo.CurrentCulture).Trim();

            int nDigits = (digits[0] == '-' ? 1 : 0);

            for (int idx = digits.Length - 1; idx >= nDigits; idx--)
            {
                int d = (int)digits[idx];
                if (d >= '0' && d <= '9')
                {
                    d -= '0';
                }
                else if (d >= 'A' && d <= 'Z')
                {
                    d = (d - 'A') + 10;
                }
                else
                {
                    throw new ArgumentOutOfRangeException("digits");
                }

                if (d >= radix)
                {
                    throw new ArgumentOutOfRangeException("digits");
                }
                result += (multiplier * d);
                multiplier *= radix;
            }

            if (digits[0] == '-')
            {
                result = -result;
            }

            this.m_digits = result.m_digits;
        }
Beispiel #10
0
 /// <summary>
 /// Create a BigInteger with an integer value of 0.
 /// </summary>
 public BigInteger()
 {
     m_digits = new DigitsArray(1, 1);
 }
Beispiel #11
0
 /// <summary>
 /// Creates a BigInteger with the value of the operand. Can never be negative.
 /// </summary>
 /// <param name="number">A unsigned long.</param>
 public BigInteger(ulong number)
 {
     m_digits = new DigitsArray((8 / DigitsArray.DataSizeOf) + 1, 0);
     while (number != 0 && m_digits.DataUsed < m_digits.Count)
     {
         m_digits[m_digits.DataUsed] = (DType)(number & DigitsArray.AllBits);
         number >>= DigitsArray.DataSizeBits;
         m_digits.DataUsed++;
     }
     m_digits.ResetDataUsed();
 }
Beispiel #12
0
 internal DigitsArray(DigitsArray copyFrom)
 {
     Allocate(copyFrom.Count, copyFrom.DataUsed);
     Array.Copy(copyFrom.m_data, 0, m_data, 0, copyFrom.Count);
 }
Beispiel #13
0
        public static BigInteger operator >>(BigInteger leftSide, int shiftCount)
        {
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide");
            }

            DigitsArray da = new DigitsArray(leftSide.m_digits);
            da.DataUsed = da.ShiftRight(shiftCount);

            if (leftSide.IsNegative)
            {
                for (int i = da.Count - 1; i >= da.DataUsed; i--)
                {
                    da[i] = DigitsArray.AllBits;
                }

                DType mask = DigitsArray.HiBitSet;
                for (int i = 0; i < DigitsArray.DataSizeBits; i++)
                {
                    if ((da[da.DataUsed - 1] & mask) == DigitsArray.HiBitSet)
                    {
                        break;
                    }
                    da[da.DataUsed - 1] |= mask;
                    mask >>= 1;
                }
                da.DataUsed = da.Count;
            }

            return new BigInteger(da);
        }
Beispiel #14
0
        public static BigInteger operator <<(BigInteger leftSide, int shiftCount)
        {
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide");
            }

            DigitsArray da = new DigitsArray(leftSide.m_digits);
            da.DataUsed = da.ShiftLeftWithoutOverflow(shiftCount);

            return new BigInteger(da);
        }
Beispiel #15
0
        public static BigInteger operator ~(BigInteger leftSide)
        {
            DigitsArray da = new DigitsArray(leftSide.m_digits.Count);
            for (int idx = 0; idx < da.Count; idx++)
            {
                da[idx] = (DType)(~(leftSide.m_digits[idx]));
            }

            return new BigInteger(da);
        }
Beispiel #16
0
 public static BigInteger operator ^(BigInteger leftSide, BigInteger rightSide)
 {
     int len = System.Math.Max(leftSide.m_digits.DataUsed, rightSide.m_digits.DataUsed);
     DigitsArray da = new DigitsArray(len, len);
     for (int idx = 0; idx < len; idx++)
     {
         da[idx] = (DType)(leftSide.m_digits[idx] ^ rightSide.m_digits[idx]);
     }
     return new BigInteger(da);
 }