Merge branch 'BigIntegerParse'
[mono.git] / mcs / class / System.Numerics / System.Numerics / BigInteger.cs
index 4e86beac426a17708884d6c89f2a5e6a5138cbae..4205d8ccdca4ce8fe1b718d0546ea08550a6b9eb 100644 (file)
-/* ****************************************************************************\r
- *\r
- * Copyright (c) Microsoft Corporation. \r
- *\r
- * This source code is subject to terms and conditions of the Microsoft Public License. A \r
- * copy of the license can be found in the License.html file at the root of this distribution. If \r
- * you cannot locate the  Microsoft Public License, please send an email to \r
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound \r
- * by the terms of the Microsoft Public License.\r
- *\r
- * You must not remove this notice, or any other, from this software.\r
- *\r
- *\r
- * ***************************************************************************/\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Diagnostics;\r
-using System.Diagnostics.CodeAnalysis;\r
-using System.Globalization;\r
-using System.Text;\r
-\r
-namespace Microsoft.Scripting.Math {\r
-    /// <summary>\r
-    /// arbitrary precision integers\r
-    /// </summary>\r
-    [Serializable]\r
-    public sealed class BigInteger : IFormattable, IComparable, IConvertible, IEquatable<BigInteger> {\r
-        private const int BitsPerDigit = 32;\r
-        private const ulong Base = 0x100000000;\r
-\r
-        // -1 if negative, +1 if positive, 0 if zero.\r
-        private readonly short sign;\r
-\r
-        // Non-null. data[0] is the least significant 32 bits.\r
-        private readonly uint[] data;\r
-\r
-        [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]\r
-        public static readonly BigInteger Zero = new BigInteger(0, new uint[0]);\r
-        [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]\r
-        public static readonly BigInteger One = new BigInteger(+1, new uint[] { 1 });\r
-        private const int bias = 1075;\r
-\r
-        [CLSCompliant(false)]\r
-        public static BigInteger Create(ulong v) {\r
-            return new BigInteger(+1, (uint)v, (uint)(v >> BitsPerDigit));\r
-        }\r
-\r
-        [CLSCompliant(false)]\r
-        public static BigInteger Create(uint v) {\r
-            if (v == 0) return Zero;\r
-            else if (v == 1) return One;\r
-            else return new BigInteger(+1, v);\r
-        }\r
-\r
-        public static BigInteger Create(long v) {\r
-            ulong x;\r
-            int s = +1;\r
-            if (v < 0) {\r
-                x = (ulong)-v; s = -1;\r
-            } else {\r
-                x = (ulong)v;\r
-            }\r
-\r
-            return new BigInteger(s, (uint)x, (uint)(x >> BitsPerDigit));\r
-        }\r
-\r
-        public static BigInteger Create(int v) {\r
-            if (v == 0) return Zero;\r
-            else if (v == 1) return One;\r
-            else if (v < 0) return new BigInteger(-1, (uint)-v);\r
-            else return new BigInteger(+1, (uint)v);\r
-        }\r
-\r
-        private const Int32 DecimalScaleFactorMask = 0x00FF0000;\r
-        private const Int32 DecimalSignMask = unchecked((Int32)0x80000000);\r
-\r
-        public static BigInteger Create(decimal v) {\r
-            // First truncate to get scale to 0 and extract bits\r
-            int[] bits = Decimal.GetBits(Decimal.Truncate(v));\r
-\r
-            Debug.Assert(bits.Length == 4 && (bits[3] & DecimalScaleFactorMask) == 0);\r
-\r
-            int size = 3;\r
-            while (size > 0 && bits[size - 1] == 0) size--;\r
-\r
-            if (size == 0) {\r
-                return BigInteger.Zero;\r
-            }\r
-\r
-            UInt32[] array = new UInt32[size];\r
-            array[0] = (UInt32)bits[0];\r
-            if (size > 1) array[1] = (UInt32)bits[1];\r
-            if (size > 2) array[2] = (UInt32)bits[2];\r
-\r
-            return new BigInteger(((bits[3] & DecimalSignMask) != 0) ? -1 : +1, array);\r
-        }\r
-\r
-        /// <summary>\r
-        /// Create a BigInteger from a little-endian twos-complement byte array\r
-        /// (inverse of ToByteArray())\r
-        /// </summary>\r
-        public static BigInteger Create(byte[] v) {\r
-           if (v == null)\r
-               throw new ArgumentNullException ("v");\r
-            if (v.Length == 0) return Create(0);\r
-\r
-            int byteCount = v.Length;\r
-            int unalignedBytes = byteCount % 4;\r
-            int dwordCount = byteCount / 4 + (unalignedBytes == 0 ? 0 : 1);\r
-            uint[] data = new uint[dwordCount];\r
-\r
-            bool isNegative = (v[byteCount - 1] & 0x80) == 0x80;\r
-\r
-            bool isZero = true;\r
-\r
-            // Copy all dwords, except but don't do the last one if it's not a full four bytes\r
-            int curDword, curByte, byteInDword;\r
-            curByte = 3;\r
-            for (curDword = 0; curDword < dwordCount - (unalignedBytes == 0 ? 0 : 1); curDword++) {\r
-                byteInDword = 0;\r
-                while (byteInDword < 4) {\r
-                    if (v[curByte] != 0x00) isZero = false;\r
-                    data[curDword] <<= 8;\r
-                    data[curDword] |= v[curByte];\r
-                    curByte--;\r
-                    byteInDword++;\r
-                }\r
-                curByte += 8;\r
-            }\r
-\r
-            // Copy the last dword specially if it's not aligned\r
-            if (unalignedBytes != 0) {\r
-                if (isNegative) data[dwordCount - 1] = 0xffffffff;\r
-                for (curByte = byteCount - 1; curByte >= byteCount - unalignedBytes; curByte--) {\r
-                    if (v[curByte] != 0x00) isZero = false;\r
-                    data[curDword] <<= 8;\r
-                    data[curDword] |= v[curByte];\r
-                }\r
-            }\r
-\r
-            if (isZero) return Zero;\r
-\r
-            if (isNegative) {\r
-                makeTwosComplement(data);\r
-                return new BigInteger(-1, data);\r
-            }\r
-            return new BigInteger(1, data);\r
-        }\r
-\r
-\r
-        private static bool Negative(byte[] v) {\r
-            return ((v[7] & 0x80) != 0);\r
-        }\r
-\r
-        private static ushort Exponent(byte[] v) {\r
-            return (ushort)((((ushort)(v[7] & 0x7F)) << (ushort)4) | (((ushort)(v[6] & 0xF0)) >> 4));\r
-        }\r
-\r
-        private static ulong Mantissa(byte[] v) {\r
-            uint i1 = ((uint)v[0] | ((uint)v[1] << 8) | ((uint)v[2] << 16) | ((uint)v[3] << 24));\r
-            uint i2 = ((uint)v[4] | ((uint)v[5] << 8) | ((uint)(v[6] & 0xF) << 16));\r
-\r
-            return (ulong)((ulong)i1 | ((ulong)i2 << 32));\r
-        }\r
-\r
-        public static BigInteger Create(double v) {\r
-            if (Double.IsNaN(v) || Double.IsInfinity(v)) {\r
-                throw new OverflowException();\r
-            }\r
-\r
-            byte[] bytes = System.BitConverter.GetBytes(v);\r
-            ulong mantissa = Mantissa(bytes);\r
-            if (mantissa == 0) {\r
-                // 1.0 * 2**exp, we have a power of 2\r
-                int exponent = Exponent(bytes);\r
-                if (exponent == 0) return Zero;\r
-\r
-                BigInteger res = Negative(bytes) ? Negate(One) : One;\r
-                res = res << (exponent - 0x3ff);\r
-                return res;\r
-            } else {\r
-                // 1.mantissa * 2**exp\r
-                int exponent = Exponent(bytes);\r
-                mantissa |= 0x10000000000000ul;\r
-                BigInteger res = BigInteger.Create(mantissa);\r
-                res = exponent > bias ? res << (exponent - bias) : res >> (bias - exponent);\r
-                return Negative(bytes) ? res * (-1) : res;\r
-            }\r
-        }\r
-\r
-        public static implicit operator BigInteger(byte i) {\r
-            return Create((uint)i);\r
-        }\r
-\r
-        [CLSCompliant(false)]\r
-        public static implicit operator BigInteger(sbyte i) {\r
-            return Create((int)i);\r
-        }\r
-\r
-        public static implicit operator BigInteger(short i) {\r
-            return Create((int)i);\r
-        }\r
-\r
-        [CLSCompliant(false)]\r
-        public static implicit operator BigInteger(ushort i) {\r
-            return Create((uint)i);\r
-        }\r
-\r
-        [CLSCompliant(false)]\r
-        public static implicit operator BigInteger(uint i) {\r
-            return Create(i);\r
-        }\r
-\r
-        public static implicit operator BigInteger(int i) {\r
-            return Create(i);\r
-        }\r
-\r
-        [CLSCompliant(false)]\r
-        public static implicit operator BigInteger(ulong i) {\r
-            return Create(i);\r
-        }\r
-\r
-        public static implicit operator BigInteger(long i) {\r
-            return Create(i);\r
-        }\r
-\r
-        public static implicit operator BigInteger(decimal i) {\r
-            return Create(i);\r
-        }\r
-\r
-        public static explicit operator BigInteger(double self) {\r
-            return Create(self);\r
-        }\r
-\r
-        public static explicit operator BigInteger(float self) {\r
-            return Create((double)self);\r
-        }\r
-\r
-        public static explicit operator double(BigInteger self) {\r
-            if (object.ReferenceEquals(self, null)) {\r
-                throw new ArgumentNullException("self");\r
-            }\r
-            return self.ToFloat64();\r
-        }\r
-\r
-        public static explicit operator float(BigInteger self) {\r
-            if (object.ReferenceEquals(self, null)) {\r
-                throw new ArgumentNullException("self");\r
-            }\r
-            return checked((float)self.ToFloat64());\r
-        }\r
-\r
-        public static explicit operator decimal(BigInteger self) {\r
-            decimal res;\r
-            if (self.AsDecimal(out res)) {\r
-                return res;\r
-            }\r
-            throw new OverflowException();\r
-        }\r
-\r
-        public static explicit operator byte(BigInteger self) {\r
-            int tmp;\r
-            if (self.AsInt32(out tmp)) {\r
-                return checked((byte)tmp);\r
-            }\r
-            throw new OverflowException();\r
-        }\r
-\r
-        [CLSCompliant(false)]\r
-        public static explicit operator sbyte(BigInteger self) {\r
-            int tmp;\r
-            if (self.AsInt32(out tmp)) {\r
-                return checked((sbyte)tmp);\r
-            }\r
-            throw new OverflowException();\r
-        }\r
-\r
-        [CLSCompliant(false)]\r
-        public static explicit operator UInt16(BigInteger self) {\r
-            int tmp;\r
-            if (self.AsInt32(out tmp)) {\r
-                return checked((UInt16)tmp);\r
-            }\r
-            throw new OverflowException();\r
-        }\r
-\r
-        public static explicit operator Int16(BigInteger self) {\r
-            int tmp;\r
-            if (self.AsInt32(out tmp)) {\r
-                return checked((Int16)tmp);\r
-            }\r
-            throw new OverflowException();\r
-        }\r
-\r
-        [CLSCompliant(false)]\r
-        public static explicit operator UInt32(BigInteger self) {\r
-            uint tmp;\r
-            if (self.AsUInt32(out tmp)) {\r
-                return tmp;\r
-            }\r
-            throw new OverflowException();\r
-        }\r
-\r
-        public static explicit operator Int32(BigInteger self) {\r
-            int tmp;\r
-            if (self.AsInt32(out tmp)) {\r
-                return tmp;\r
-            }\r
-            throw new OverflowException();\r
-        }\r
-\r
-        public static explicit operator Int64(BigInteger self) {\r
-            long tmp;\r
-            if (self.AsInt64(out tmp)) {\r
-                return tmp;\r
-            }\r
-            throw new OverflowException();\r
-        }\r
-\r
-        [CLSCompliant(false)]\r
-        public static explicit operator UInt64(BigInteger self) {\r
-            ulong tmp;\r
-            if (self.AsUInt64(out tmp)) {\r
-                return tmp;\r
-            }\r
-            throw new OverflowException();\r
-        }\r
-\r
-        public BigInteger(BigInteger copy) {\r
-            if (object.ReferenceEquals(copy, null)) {\r
-                throw new ArgumentNullException("copy");\r
-            }\r
-            this.sign = copy.sign;\r
-            this.data = copy.data;\r
-        }\r
-\r
-        [CLSCompliant(false)]\r
-        public BigInteger(int sign, params uint[] data) {\r
-           if (data == null)\r
-               throw new ArgumentNullException ("data");\r
-            if (!(sign >= -1 && sign <= +1))\r
-               throw new ArgumentException ("sign");\r
-            int length = GetLength(data);\r
-           if (!(length == 0 || sign != 0))\r
-               throw new ArgumentException ("sign");\r
-            \r
-            this.data = data;\r
-            this.sign = (short)(length == 0 ? 0 : sign);\r
-        }\r
-\r
-        /// <summary>\r
-        /// Return the magnitude of this BigInteger as an array of zero or more uints.\r
-        /// Element zero is the value of the least significant four bytes, element one is\r
-        /// the value of the four next most significant bytes, etc.\r
-        /// \r
-        /// The returned data is the unsigned magnitude of the number. To determine the sign,\r
-        /// use GetSign().\r
-        /// \r
-        /// It is guaranteed that the highest element of the returned array is never zero.\r
-        /// This means that if the value of this BigInteger is zero, a zero-length array\r
-        /// is returned.\r
-        /// </summary>\r
-        [CLSCompliant(false)]\r
-        public uint[] GetWords() {\r
-            if (sign == 0) return new uint[0];\r
-            int w = GetWordCount();\r
-            uint[] bits = new uint[w];\r
-            Array.Copy(data, bits, w);\r
-            return bits;\r
-        }\r
-\r
-        [CLSCompliant(false)]\r
-        public uint GetWord(int index) {\r
-            return data[index];\r
-        }\r
-\r
-        public int GetBitCount() {\r
-            if (IsZero()) {\r
-                return 0;\r
-            }\r
-            int w = GetWordCount() - 1;\r
-            uint b = data[w];\r
-            Debug.Assert(b > 0);\r
-            int result = w * 32;\r
-            do {\r
-                b >>= 1;\r
-                result++;\r
-            } while (b > 0);\r
-\r
-            return result;\r
-        }\r
-\r
-        public int GetByteCount() {\r
-            return (GetBitCount() + 7) / 8;\r
-        }\r
-\r
-        /// <summary>\r
-        /// Return the sign of this BigInteger: -1, 0, or 1.\r
-        /// </summary>\r
-        public short Sign {\r
-            get {\r
-                return sign;\r
-            }\r
-        }\r
-\r
-        public bool AsInt64(out long ret) {\r
-            ret = 0;\r
-            if (sign == 0) return true;\r
-            if (GetWordCount() > 2) return false;\r
-            if (data.Length == 1) {\r
-                ret = sign * (long)data[0];\r
-                return true;\r
-            }\r
-            ulong tmp = (((ulong)data[1]) << 32 | (ulong)data[0]);\r
-            if (tmp > 0x8000000000000000) return false;\r
-            if (tmp == 0x8000000000000000 && sign == 1) return false;\r
-            ret = ((long)tmp) * sign;\r
-            return true;\r
-        }\r
-\r
-        [CLSCompliant(false)]\r
-        public bool AsUInt32(out uint ret) {\r
-            ret = 0;\r
-            if (sign == 0) return true;\r
-            if (sign < 0) return false;\r
-            if (GetWordCount() > 1) return false;\r
-            ret = data[0];\r
-            return true;\r
-        }\r
-\r
-        [CLSCompliant(false)]\r
-        public bool AsUInt64(out ulong ret) {\r
-            ret = 0;\r
-            if (sign == 0) return true;\r
-            if (sign < 0) return false;\r
-            if (GetWordCount() > 2) return false;\r
-            ret = (ulong)data[0];\r
-            if (data.Length > 1) {\r
-                ret |= ((ulong)data[1]) << 32;\r
-            }\r
-            return true;\r
-        }\r
-\r
-        public bool AsInt32(out int ret) {\r
-            ret = 0;\r
-            if (sign == 0) return true;\r
-            if (GetWordCount() > 1) return false;\r
-            if (data[0] > 0x80000000) return false;\r
-            if (data[0] == 0x80000000 && sign == 1) return false;\r
-            ret = (int)data[0];\r
-            ret *= sign;\r
-            return true;\r
-        }\r
-\r
-        public bool AsDecimal(out Decimal ret) {\r
-            if (sign == 0) {\r
-                ret = Decimal.Zero;\r
-                return true;\r
-            }\r
-\r
-            int length = GetWordCount();\r
-            if (length > 3) {\r
-                ret = default(Decimal);\r
-                return false;\r
-            }\r
-\r
-            int lo = 0, mi = 0, hi = 0;\r
-            if (length > 2) hi = (Int32)data[2];\r
-            if (length > 1) mi = (Int32)data[1];\r
-            if (length > 0) lo = (Int32)data[0];\r
-\r
-            ret = new Decimal(lo, mi, hi, sign < 0, 0);\r
-            return true;\r
-        }\r
-\r
-\r
-        [CLSCompliant(false)]\r
-        public uint ToUInt32() {\r
-            uint ret;\r
-            if (AsUInt32(out ret)) return ret;\r
-            throw new OverflowException("big integer won't fit into uint");\r
-        }\r
-\r
-        public int ToInt32() {\r
-            int ret;\r
-            if (AsInt32(out ret)) return ret;\r
-            throw new OverflowException("big integer won't fit into int");\r
-        }\r
-\r
-        public decimal ToDecimal() {\r
-            decimal ret;\r
-            if (AsDecimal(out ret)) return ret;\r
-            throw new OverflowException("big integer won't fit into decimal");\r
-        }\r
-\r
-        [CLSCompliant(false)]\r
-        public ulong ToUInt64() {\r
-            ulong ret;\r
-            if (AsUInt64(out ret)) return ret;\r
-            throw new OverflowException("big integer won't fit into ulong");\r
-        }\r
-\r
-        public long ToInt64() {\r
-            long ret;\r
-            if (AsInt64(out ret)) return ret;\r
-            throw new OverflowException("big integer won't fit into long");\r
-        }\r
-\r
-        public bool TryToFloat64(out double result) {\r
-            return double.TryParse(ToString(10),\r
-                System.Globalization.NumberStyles.Number,\r
-                System.Globalization.CultureInfo.InvariantCulture.NumberFormat,\r
-                out result);\r
-        }\r
-\r
-        public double ToFloat64() {\r
-            return double.Parse(\r
-                ToString(10),\r
-                System.Globalization.CultureInfo.InvariantCulture.NumberFormat\r
-                );\r
-        }\r
-\r
-        public int GetWordCount() {\r
-            return GetLength(data);\r
-        }\r
-\r
-        private static int GetLength(uint[] data) {\r
-            int ret = data.Length - 1;\r
-            while (ret >= 0 && data[ret] == 0) ret--;\r
-            return ret + 1;\r
-        }\r
-\r
-\r
-        private static uint[] copy(uint[] v) {\r
-            uint[] ret = new uint[v.Length];\r
-            Array.Copy(v, ret, v.Length);\r
-            return ret;\r
-        }\r
-\r
-        private static uint[] resize(uint[] v, int len) {\r
-            if (v.Length == len) return v;\r
-            uint[] ret = new uint[len];\r
-            int n = System.Math.Min(v.Length, len);\r
-            for (int i = 0; i < n; i++) {\r
-                ret[i] = v[i];\r
-            }\r
-            return ret;\r
-        }\r
-\r
-        private static uint[] InternalAdd(uint[] x, int xl, uint[] y, int yl) {\r
-            Debug.Assert(xl >= yl);\r
-            uint[] z = new uint[xl];\r
-\r
-            int i;\r
-            ulong sum = 0;\r
-            for (i = 0; i < yl; i++) {\r
-                sum = sum + x[i] + y[i];\r
-                z[i] = (uint)sum;\r
-                sum >>= BitsPerDigit;\r
-            }\r
-\r
-            for (; i < xl && sum != 0; i++) {\r
-                sum = sum + x[i];\r
-                z[i] = (uint)sum;\r
-                sum >>= BitsPerDigit;\r
-            }\r
-            if (sum != 0) {\r
-                z = resize(z, xl + 1);\r
-                z[i] = (uint)sum;\r
-            } else {\r
-                for (; i < xl; i++) {\r
-                    z[i] = x[i];\r
-                }\r
-            }\r
-            return z;\r
-        }\r
-\r
-        private static uint[] sub(uint[] x, int xl, uint[] y, int yl) {\r
-            Debug.Assert(xl >= yl);\r
-            uint[] z = new uint[xl];\r
-\r
-            int i;\r
-            bool borrow = false;\r
-            for (i = 0; i < yl; i++) {\r
-                uint xi = x[i];\r
-                uint yi = y[i];\r
-                if (borrow) {\r
-                    if (xi == 0) {\r
-                        xi = 0xffffffff;\r
-                        borrow = true;\r
-                    } else {\r
-                        xi -= 1;\r
-                        borrow = false;\r
-                    }\r
-                }\r
-                if (yi > xi) borrow = true;\r
-                z[i] = xi - yi;\r
-            }\r
-\r
-            if (borrow) {\r
-                for (; i < xl; i++) {\r
-                    uint xi = x[i];\r
-                    z[i] = xi - 1;\r
-                    if (xi != 0) { i++; break; }\r
-                }\r
-            }\r
-            for (; i < xl; i++) {\r
-                z[i] = x[i];\r
-            }\r
-            return z;  // may have leading zeros\r
-        }\r
-\r
-        private static uint[] add0(uint[] x, int xl, uint[] y, int yl) {\r
-            if (xl >= yl) return InternalAdd(x, xl, y, yl);\r
-            else return InternalAdd(y, yl, x, xl);\r
-        }\r
-\r
-        public static int Compare(BigInteger x, BigInteger y) {\r
-            if (object.ReferenceEquals(x, null)) {\r
-                throw new ArgumentNullException("x");\r
-            }\r
-            if (object.ReferenceEquals(y, null)) {\r
-                throw new ArgumentNullException("y");\r
-            }\r
-            if (x.sign == y.sign) {\r
-                int xl = x.GetWordCount();\r
-                int yl = y.GetWordCount();\r
-                if (xl == yl) {\r
-                    for (int i = xl - 1; i >= 0; i--) {\r
-                        if (x.data[i] == y.data[i]) continue;\r
-                        return x.data[i] > y.data[i] ? x.sign : -x.sign;\r
-                    }\r
-                    return 0;\r
-                } else {\r
-                    return xl > yl ? +x.sign : -x.sign;\r
-                }\r
-            } else {\r
-                return x.sign > y.sign ? +1 : -1;\r
-            }\r
-        }\r
-\r
-        public static bool operator ==(BigInteger x, int y) {\r
-            return x == (BigInteger)y;\r
-        }\r
-\r
-        public static bool operator !=(BigInteger x, int y) {\r
-            return !(x == y);\r
-        }\r
-\r
-        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")] // TODO: fix\r
-        public static bool operator ==(BigInteger x, double y) {\r
-            if (object.ReferenceEquals(x, null)) {\r
-                throw new ArgumentNullException("x");\r
-            }\r
-\r
-            // we can hold all double values, but not all double values\r
-            // can hold BigInteger values, and we may lose precision.  Convert\r
-            // the double to a big int, then compare.\r
-\r
-            if ((y % 1) != 0) return false;  // not a whole number, can't be equal\r
-\r
-            return x == BigInteger.Create(y);\r
-        }\r
-\r
-        public static bool operator ==(double x, BigInteger y) {\r
-            return y == x;\r
-        }\r
-\r
-        public static bool operator !=(BigInteger x, double y) {\r
-            return !(x == y);\r
-        }\r
-\r
-        public static bool operator !=(double x, BigInteger y) {\r
-            return !(x == y);\r
-        }\r
-\r
-\r
-        public static bool operator ==(BigInteger x, BigInteger y) {\r
-            return Compare(x, y) == 0;\r
-        }\r
-\r
-        public static bool operator !=(BigInteger x, BigInteger y) {\r
-            return Compare(x, y) != 0;\r
-        }\r
-        public static bool operator <(BigInteger x, BigInteger y) {\r
-            return Compare(x, y) < 0;\r
-        }\r
-        public static bool operator <=(BigInteger x, BigInteger y) {\r
-            return Compare(x, y) <= 0;\r
-        }\r
-        public static bool operator >(BigInteger x, BigInteger y) {\r
-            return Compare(x, y) > 0;\r
-        }\r
-        public static bool operator >=(BigInteger x, BigInteger y) {\r
-            return Compare(x, y) >= 0;\r
-        }\r
-\r
-        public static BigInteger Add(BigInteger x, BigInteger y) {\r
-            return x + y;\r
-        }\r
-\r
-        public static BigInteger operator +(BigInteger x, BigInteger y) {\r
-            if (object.ReferenceEquals(x, null)) {\r
-                throw new ArgumentNullException("x");\r
-            }\r
-            if (object.ReferenceEquals(y, null)) {\r
-                throw new ArgumentNullException("y");\r
-            }\r
-\r
-            if (x.sign == y.sign) {\r
-                return new BigInteger(x.sign, add0(x.data, x.GetWordCount(), y.data, y.GetWordCount()));\r
-            } else {\r
-                return x - new BigInteger(-y.sign, y.data);  //??? performance issue\r
-            }\r
-        }\r
-\r
-        public static BigInteger Subtract(BigInteger x, BigInteger y) {\r
-            return x - y;\r
-        }\r
-\r
-        public static BigInteger operator -(BigInteger x, BigInteger y) {\r
-            int c = Compare(x, y);\r
-            if (c == 0) return Zero;\r
-\r
-            if (x.sign == y.sign) {\r
-                uint[] z;\r
-                switch (c * x.sign) {\r
-                    case +1:\r
-                        z = sub(x.data, x.GetWordCount(), y.data, y.GetWordCount());\r
-                        break;\r
-                    case -1:\r
-                        z = sub(y.data, y.GetWordCount(), x.data, x.GetWordCount());\r
-                        break;\r
-                    default:\r
-                        return Zero;\r
-                }\r
-                return new BigInteger(c, z);\r
-            } else {\r
-                uint[] z = add0(x.data, x.GetWordCount(), y.data, y.GetWordCount());\r
-                return new BigInteger(c, z);\r
-            }\r
-        }\r
-\r
-        public static BigInteger Multiply(BigInteger x, BigInteger y) {\r
-            return x * y;\r
-        }\r
-\r
-        public static BigInteger operator *(BigInteger x, BigInteger y) {\r
-            if (object.ReferenceEquals(x, null)) {\r
-                throw new ArgumentNullException("x");\r
-            }\r
-            if (object.ReferenceEquals(y, null)) {\r
-                throw new ArgumentNullException("y");\r
-            }\r
-            int xl = x.GetWordCount();\r
-            int yl = y.GetWordCount();\r
-            int zl = xl + yl;\r
-            uint[] xd = x.data, yd = y.data, zd = new uint[zl];\r
-\r
-            for (int xi = 0; xi < xl; xi++) {\r
-                uint xv = xd[xi];\r
-                int zi = xi;\r
-                ulong carry = 0;\r
-                for (int yi = 0; yi < yl; yi++) {\r
-                    carry = carry + ((ulong)xv) * yd[yi] + zd[zi];\r
-                    zd[zi++] = (uint)carry;\r
-                    carry >>= BitsPerDigit;\r
-                }\r
-                while (carry != 0) {\r
-                    carry += zd[zi];\r
-                    zd[zi++] = (uint)carry;\r
-                    carry >>= BitsPerDigit;\r
-                }\r
-            }\r
-\r
-            return new BigInteger(x.sign * y.sign, zd);\r
-        }\r
-\r
-        public static BigInteger Divide(BigInteger x, BigInteger y) {\r
-            return x / y;\r
-        }\r
-\r
-        public static BigInteger operator /(BigInteger x, BigInteger y) {\r
-            BigInteger dummy;\r
-            return DivRem(x, y, out dummy);\r
-        }\r
-\r
-        public static BigInteger Mod(BigInteger x, BigInteger y) {\r
-            return x % y;\r
-        }\r
-\r
-        public static BigInteger operator %(BigInteger x, BigInteger y) {\r
-            BigInteger ret;\r
-            DivRem(x, y, out ret);\r
-            return ret;\r
-        }\r
-\r
-        private static int GetNormalizeShift(uint value) {\r
-            int shift = 0;\r
-\r
-            if ((value & 0xFFFF0000) == 0) { value <<= 16; shift += 16; }\r
-            if ((value & 0xFF000000) == 0) { value <<= 8; shift += 8; }\r
-            if ((value & 0xF0000000) == 0) { value <<= 4; shift += 4; }\r
-            if ((value & 0xC0000000) == 0) { value <<= 2; shift += 2; }\r
-            if ((value & 0x80000000) == 0) { value <<= 1; shift += 1; }\r
-\r
-            return shift;\r
-        }\r
-\r
-        [Conditional("DEBUG")]\r
-        [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "Microsoft.Scripting.Math.BigInteger")]\r
-        private static void TestNormalize(uint[] u, uint[] un, int shift) {\r
-            BigInteger i = new BigInteger(1, u);\r
-            BigInteger j = new BigInteger(1, un);\r
-            BigInteger k = j >> shift;\r
-\r
-            Debug.Assert(i == k);\r
-        }\r
-\r
-        [Conditional("DEBUG")]\r
-        private static void TestDivisionStep(uint[] un, uint[] vn, uint[] q, uint[] u, uint[] v) {\r
-            int n = GetLength(v);\r
-            int shift = GetNormalizeShift(v[n - 1]);\r
-\r
-            BigInteger uni = new BigInteger(1, un);\r
-            BigInteger vni = new BigInteger(1, vn);\r
-            BigInteger qi = new BigInteger(1, q);\r
-            BigInteger ui = new BigInteger(1, u);\r
-\r
-            BigInteger expected = vni * qi + uni;\r
-            BigInteger usi = ui << shift;\r
-\r
-            Debug.Assert(expected == usi);\r
-        }\r
-\r
-        [Conditional("DEBUG")]\r
-        [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "Microsoft.Scripting.Math.BigInteger")]\r
-        private static void TestResult(uint[] u, uint[] v, uint[] q, uint[] r) {\r
-            BigInteger ui = new BigInteger(1, u);\r
-            BigInteger vi = new BigInteger(1, v);\r
-            BigInteger qi = new BigInteger(1, q);\r
-            BigInteger ri = new BigInteger(1, r);\r
-\r
-            BigInteger viqi = vi * qi;\r
-            BigInteger expected = viqi + ri;\r
-            Debug.Assert(ui == expected);\r
-            Debug.Assert(ri < vi);\r
-        }\r
-\r
-        private static void Normalize(uint[] u, int l, uint[] un, int shift) {\r
-            Debug.Assert(un.Length == l || un.Length == l + 1);\r
-            Debug.Assert(un.Length == l + 1 || ((u[l - 1] << shift) >> shift) == u[l - 1]);\r
-            Debug.Assert(0 <= shift && shift < 32);\r
-\r
-            uint carry = 0;\r
-            int i;\r
-            if (shift > 0) {\r
-                int rshift = BitsPerDigit - shift;\r
-                for (i = 0; i < l; i++) {\r
-                    uint ui = u[i];\r
-                    un[i] = (ui << shift) | carry;\r
-                    carry = ui >> rshift;\r
-                }\r
-            } else {\r
-                for (i = 0; i < l; i++) {\r
-                    un[i] = u[i];\r
-                }\r
-            }\r
-\r
-            while (i < un.Length) {\r
-                un[i++] = 0;\r
-            }\r
-\r
-            if (carry != 0) {\r
-                Debug.Assert(l == un.Length - 1);\r
-                un[l] = carry;\r
-            }\r
-\r
-            TestNormalize(u, un, shift);\r
-        }\r
-\r
-        private static void Unnormalize(uint[] un, out uint[] r, int shift) {\r
-            Debug.Assert(0 <= shift && shift < 32);\r
-\r
-            int length = GetLength(un);\r
-            r = new uint[length];\r
-\r
-            if (shift > 0) {\r
-                int lshift = 32 - shift;\r
-                uint carry = 0;\r
-                for (int i = length - 1; i >= 0; i--) {\r
-                    uint uni = un[i];\r
-                    r[i] = (uni >> shift) | carry;\r
-                    carry = (uni << lshift);\r
-                }\r
-            } else {\r
-                for (int i = 0; i < length; i++) {\r
-                    r[i] = un[i];\r
-                }\r
-            }\r
-\r
-            TestNormalize(r, un, shift);\r
-        }\r
-\r
-        private static void DivModUnsigned(uint[] u, uint[] v, out uint[] q, out uint[] r) {\r
-            int m = GetLength(u);\r
-            int n = GetLength(v);\r
-\r
-            if (n <= 1) {\r
-                if (n == 0) {\r
-                    throw new DivideByZeroException();\r
-                }\r
-\r
-                //  Divide by single digit\r
-                //\r
-                ulong rem = 0;\r
-                uint v0 = v[0];\r
-                q = new uint[m];\r
-                r = new uint[1];\r
-\r
-                for (int j = m - 1; j >= 0; j--) {\r
-                    rem *= Base;\r
-                    rem += u[j];\r
-\r
-                    ulong div = rem / v0;\r
-                    rem -= div * v0;\r
-                    q[j] = (uint)div;\r
-                }\r
-                r[0] = (uint)rem;\r
-            } else if (m >= n) {\r
-                int shift = GetNormalizeShift(v[n - 1]);\r
-\r
-                uint[] un = new uint[m + 1];\r
-                uint[] vn = new uint[n];\r
-\r
-                Normalize(u, m, un, shift);\r
-                Normalize(v, n, vn, shift);\r
-\r
-                q = new uint[m - n + 1];\r
-                r = null;\r
-\r
-                TestDivisionStep(un, vn, q, u, v);\r
-\r
-                //  Main division loop\r
-                //\r
-                for (int j = m - n; j >= 0; j--) {\r
-                    ulong rr, qq;\r
-                    int i;\r
-\r
-                    rr = Base * un[j + n] + un[j + n - 1];\r
-                    qq = rr / vn[n - 1];\r
-                    rr -= qq * vn[n - 1];\r
-\r
-                    Debug.Assert((Base * un[j + n] + un[j + n - 1]) == qq * vn[n - 1] + rr);\r
-\r
-                    for (; ; ) {\r
-                        // Estimate too big ?\r
-                        //\r
-                        if ((qq >= Base) || (qq * vn[n - 2] > (rr * Base + un[j + n - 2]))) {\r
-                            qq--;\r
-                            rr += (ulong)vn[n - 1];\r
-                            if (rr < Base) continue;\r
-                        }\r
-                        break;\r
-                    }\r
-\r
-                    Debug.Assert((Base * un[j + n] + un[j + n - 1]) == qq * vn[n - 1] + rr);\r
-\r
-                    //  Multiply and subtract\r
-                    //\r
-                    long b = 0;\r
-                    long t = 0;\r
-                    for (i = 0; i < n; i++) {\r
-                        ulong p = vn[i] * qq;\r
-                        t = (long)un[i + j] - (long)(uint)p - b;\r
-                        un[i + j] = (uint)t;\r
-                        p >>= 32;\r
-                        t >>= 32;\r
-                        Debug.Assert(t == 0 || t == -1 || t == -2);\r
-                        b = (long)p - t;\r
-                    }\r
-                    t = (long)un[j + n] - b;\r
-                    un[j + n] = (uint)t;\r
-\r
-                    //  Store the calculated value\r
-                    //\r
-                    q[j] = (uint)qq;\r
-\r
-                    //  Add back vn[0..n] to un[j..j+n]\r
-                    //\r
-                    if (t < 0) {\r
-                        q[j]--;\r
-                        ulong c = 0;\r
-                        for (i = 0; i < n; i++) {\r
-                            c = (ulong)vn[i] + un[j + i] + c;\r
-                            un[j + i] = (uint)c;\r
-                            c >>= 32;\r
-                        }\r
-                        c += (ulong)un[j + n];\r
-                        un[j + n] = (uint)c;\r
-                    }\r
-\r
-                    TestDivisionStep(un, vn, q, u, v);\r
-                }\r
-\r
-                Unnormalize(un, out r, shift);\r
-\r
-                //  Test normalized value ... Call TestNormalize\r
-                //  only pass the values in different order.\r
-                //\r
-                TestNormalize(r, un, shift);\r
-            } else {\r
-                q = new uint[] { 0 };\r
-                r = u;\r
-            }\r
-\r
-            TestResult(u, v, q, r);\r
-        }\r
-\r
-        public static BigInteger DivRem(BigInteger x, BigInteger y, out BigInteger remainder) {\r
-            if (object.ReferenceEquals(x, null)) {\r
-                throw new ArgumentNullException("x");\r
-            }\r
-            if (object.ReferenceEquals(y, null)) {\r
-                throw new ArgumentNullException("y");\r
-            }\r
-\r
-            uint[] q;\r
-            uint[] r;\r
-\r
-            DivModUnsigned(x.data, y.data, out q, out r);\r
-\r
-            remainder = new BigInteger(x.sign, r);\r
-            return new BigInteger(x.sign * y.sign, q);\r
-        }\r
-\r
-        private static uint extend(uint v, ref bool seenNonZero) {\r
-            if (seenNonZero) {\r
-                return ~v;\r
-            } else {\r
-                if (v == 0) {\r
-                    return 0;\r
-                } else {\r
-                    seenNonZero = true;\r
-                    return ~v + 1;\r
-                }\r
-            }\r
-        }\r
-\r
-        private static uint getOne(bool isNeg, uint[] data, int i, ref bool seenNonZero) {\r
-            if (i < data.Length) {\r
-                uint ret = data[i];\r
-                return isNeg ? extend(ret, ref seenNonZero) : ret;\r
-            } else {\r
-                return isNeg ? uint.MaxValue : 0;\r
-            }\r
-        }\r
-\r
-        /// <summary>\r
-        /// Do an in-place twos complement of d and also return the result.\r
-        /// </summary>\r
-        private static uint[] makeTwosComplement(uint[] d) {\r
-            // first do complement and +1 as long as carry is needed\r
-            int i = 0;\r
-            uint v = 0;\r
-            for (; i < d.Length; i++) {\r
-                v = ~d[i] + 1;\r
-                d[i] = v;\r
-                if (v != 0) { i++; break; }\r
-            }\r
-\r
-            if (v != 0) {\r
-                // now ones complement is sufficient\r
-                for (; i < d.Length; i++) {\r
-                    d[i] = ~d[i];\r
-                }\r
-            } else {\r
-                //??? this is weird\r
-                d = resize(d, d.Length + 1);\r
-                d[d.Length - 1] = 1;\r
-            }\r
-            return d;\r
-        }\r
-\r
-        public static BigInteger BitwiseAnd(BigInteger x, BigInteger y) {\r
-            return x & y;\r
-        }\r
-\r
-        public static BigInteger operator &(BigInteger x, BigInteger y) {\r
-            if (object.ReferenceEquals(x, null)) {\r
-                throw new ArgumentNullException("x");\r
-            }\r
-            if (object.ReferenceEquals(y, null)) {\r
-                throw new ArgumentNullException("y");\r
-            }\r
-            int xl = x.GetWordCount(), yl = y.GetWordCount();\r
-            uint[] xd = x.data, yd = y.data;\r
-\r
-            int zl = System.Math.Max(xl, yl);\r
-            uint[] zd = new uint[zl];\r
-\r
-            bool negx = x.sign == -1, negy = y.sign == -1;\r
-            bool seenNonZeroX = false, seenNonZeroY = false;\r
-            for (int i = 0; i < zl; i++) {\r
-                uint xu = getOne(negx, xd, i, ref seenNonZeroX);\r
-                uint yu = getOne(negy, yd, i, ref seenNonZeroY);\r
-                zd[i] = xu & yu;\r
-            }\r
-\r
-            if (negx && negy) {\r
-\r
-                return new BigInteger(-1, makeTwosComplement(zd));\r
-            } else if (negx || negy) {\r
-                return new BigInteger(+1, zd);\r
-            } else {\r
-                return new BigInteger(+1, zd);\r
-            }\r
-        }\r
-\r
-        public static BigInteger BitwiseOr(BigInteger x, BigInteger y) {\r
-            return x | y;\r
-        }\r
-\r
-        public static BigInteger operator |(BigInteger x, BigInteger y) {\r
-            if (object.ReferenceEquals(x, null)) {\r
-                throw new ArgumentNullException("x");\r
-            }\r
-            if (object.ReferenceEquals(y, null)) {\r
-                throw new ArgumentNullException("y");\r
-            }\r
-            int xl = x.GetWordCount(), yl = y.GetWordCount();\r
-            uint[] xd = x.data, yd = y.data;\r
-\r
-            int zl = System.Math.Max(xl, yl);\r
-            uint[] zd = new uint[zl];\r
-\r
-            bool negx = x.sign == -1, negy = y.sign == -1;\r
-            bool seenNonZeroX = false, seenNonZeroY = false;\r
-            for (int i = 0; i < zl; i++) {\r
-                uint xu = getOne(negx, xd, i, ref seenNonZeroX);\r
-                uint yu = getOne(negy, yd, i, ref seenNonZeroY);\r
-                zd[i] = xu | yu;\r
-            }\r
-\r
-            if (negx && negy) {\r
-                return new BigInteger(-1, makeTwosComplement(zd));\r
-            } else if (negx || negy) {\r
-                return new BigInteger(-1, makeTwosComplement(zd));\r
-            } else {\r
-                return new BigInteger(+1, zd);\r
-            }\r
-        }\r
-\r
-        public static BigInteger Xor(BigInteger x, BigInteger y) {\r
-            return x ^ y;\r
-        }\r
-\r
-        public static BigInteger operator ^(BigInteger x, BigInteger y) {\r
-            if (object.ReferenceEquals(x, null)) {\r
-                throw new ArgumentNullException("x");\r
-            }\r
-            if (object.ReferenceEquals(y, null)) {\r
-                throw new ArgumentNullException("y");\r
-            }\r
-            int xl = x.GetWordCount(), yl = y.GetWordCount();\r
-            uint[] xd = x.data, yd = y.data;\r
-\r
-            int zl = System.Math.Max(xl, yl);\r
-            uint[] zd = new uint[zl];\r
-\r
-            bool negx = x.sign == -1, negy = y.sign == -1;\r
-            bool seenNonZeroX = false, seenNonZeroY = false;\r
-            for (int i = 0; i < zl; i++) {\r
-                uint xu = getOne(negx, xd, i, ref seenNonZeroX);\r
-                uint yu = getOne(negy, yd, i, ref seenNonZeroY);\r
-                zd[i] = xu ^ yu;\r
-            }\r
-\r
-            if (negx && negy) {\r
-                return new BigInteger(+1, zd);\r
-            } else if (negx || negy) {\r
-                return new BigInteger(-1, makeTwosComplement(zd));\r
-            } else {\r
-                return new BigInteger(+1, zd);\r
-            }\r
-        }\r
-\r
-        public static BigInteger LeftShift(BigInteger x, int shift) {\r
-            return x << shift;\r
-        }\r
-\r
-        public static BigInteger operator <<(BigInteger x, int shift) {\r
-            if (object.ReferenceEquals(x, null)) {\r
-                throw new ArgumentNullException("x");\r
-            }\r
-            if (shift == 0) return x;\r
-            else if (shift < 0) return x >> -shift;\r
-\r
-            int digitShift = shift / BitsPerDigit;\r
-            int smallShift = shift - (digitShift * BitsPerDigit);\r
-\r
-            int xl = x.GetWordCount();\r
-            uint[] xd = x.data;\r
-            int zl = xl + digitShift + 1;\r
-            uint[] zd = new uint[zl];\r
-\r
-            if (smallShift == 0) {\r
-                for (int i = 0; i < xl; i++) {\r
-                    zd[i + digitShift] = xd[i];\r
-                }\r
-            } else {\r
-                int carryShift = BitsPerDigit - smallShift;\r
-                uint carry = 0;\r
-                int i;\r
-                for (i = 0; i < xl; i++) {\r
-                    uint rot = xd[i];\r
-                    zd[i + digitShift] = rot << smallShift | carry;\r
-                    carry = rot >> carryShift;\r
-                }\r
-                zd[i + digitShift] = carry;\r
-            }\r
-            return new BigInteger(x.sign, zd);\r
-        }\r
-\r
-        public static BigInteger RightShift(BigInteger x, int shift) {\r
-            return x >> shift;\r
-        }\r
-\r
-        public static BigInteger operator >>(BigInteger x, int shift) {\r
-            if (object.ReferenceEquals(x, null)) {\r
-                throw new ArgumentNullException("x");\r
-            }\r
-            if (shift == 0) return x;\r
-            else if (shift < 0) return x << -shift;\r
-\r
-            int digitShift = shift / BitsPerDigit;\r
-            int smallShift = shift - (digitShift * BitsPerDigit);\r
-\r
-            int xl = x.GetWordCount();\r
-            uint[] xd = x.data;\r
-            int zl = xl - digitShift;\r
-            if (zl < 0) zl = 0;\r
-            uint[] zd = new uint[zl];\r
-\r
-            if (smallShift == 0) {\r
-                for (int i = xl - 1; i >= digitShift; i--) {\r
-                    zd[i - digitShift] = xd[i];\r
-                }\r
-            } else {\r
-                int carryShift = BitsPerDigit - smallShift;\r
-                uint carry = 0;\r
-                for (int i = xl - 1; i >= digitShift; i--) {\r
-                    uint rot = xd[i];\r
-                    zd[i - digitShift] = rot >> smallShift | carry;\r
-                    carry = rot << carryShift;\r
-                }\r
-            }\r
-            return new BigInteger(x.sign, zd);\r
-        }\r
-\r
-        public static BigInteger Negate(BigInteger x) {\r
-            return -x;\r
-        }\r
-\r
-        public static BigInteger operator -(BigInteger x) {\r
-            if (object.ReferenceEquals(x, null)) {\r
-                throw new ArgumentNullException("x");\r
-            }\r
-            return new BigInteger(-x.sign, x.data);\r
-        }\r
-\r
-        public BigInteger OnesComplement() {\r
-            return ~this;\r
-        }\r
-\r
-        public static BigInteger operator ~(BigInteger x) {\r
-            if (object.ReferenceEquals(x, null)) {\r
-                throw new ArgumentNullException("x");\r
-            }\r
-            return -(x + One);\r
-        }\r
-\r
-        public BigInteger Abs() {\r
-            if (this.sign == -1) return -this;\r
-            else return this;\r
-        }\r
-\r
-        public BigInteger Power(int exp) {\r
-            if (exp == 0) return One;\r
-            if (exp < 0) {\r
-                throw new ArgumentOutOfRangeException("exp", "exp must be >= 0");\r
-            }\r
-            BigInteger factor = this;\r
-            BigInteger result = One;\r
-            while (exp != 0) {\r
-                if ((exp & 1) != 0) result = result * factor;\r
-                if (exp == 1) break;  // avoid costly factor.square()\r
-                factor = factor.Square();\r
-                exp >>= 1;\r
-            }\r
-            return result;\r
-        }\r
-\r
-        public BigInteger ModPow(int power, BigInteger mod) {\r
-            if (object.ReferenceEquals(mod, null)) {\r
-                throw new ArgumentNullException("mod");\r
-            }\r
-\r
-            if (power < 0) {\r
-                throw new ArgumentOutOfRangeException("power", "power must be >= 0");\r
-            }\r
-            BigInteger factor = this;\r
-            BigInteger result = One % mod; // Handle special case of power=0, mod=1\r
-            while (power != 0) {\r
-                if ((power & 1) != 0) {\r
-                    result = result * factor;\r
-                    result = result % mod;\r
-                }\r
-                if (power == 1) break;  // avoid costly factor.Square()\r
-                factor = factor.Square();\r
-                factor = factor % mod;\r
-                power >>= 1;\r
-            }\r
-            return result;\r
-        }\r
-\r
-        public BigInteger ModPow(BigInteger power, BigInteger mod) {\r
-            if (object.ReferenceEquals(power, null)) {\r
-                throw new ArgumentNullException("power");\r
-            }\r
-            if (object.ReferenceEquals(mod, null)) {\r
-                throw new ArgumentNullException("mod");\r
-            }\r
-\r
-            if (power < 0) {\r
-                throw new ArgumentOutOfRangeException("power", "power must be >= 0");\r
-            }\r
-\r
-            BigInteger factor = this;\r
-            BigInteger result = One % mod;\r
-            while (power != Zero) {\r
-                if (power.IsOdd()) {\r
-                    result = result * factor;\r
-                    result = result % mod;\r
-                }\r
-                if (power == One) break;  // avoid costly factor.Square()\r
-                factor = factor.Square();\r
-                factor = factor % mod;\r
-                power >>= 1;\r
-            }\r
-            return result;\r
-        }\r
-\r
-        public BigInteger Square() {\r
-            return this * this;\r
-        }\r
-\r
-        public override string ToString() {\r
-            return ToString(10);\r
-        }\r
-\r
-        // generated by scripts/radix_generator.py\r
-        private static readonly uint[] maxCharsPerDigit = { 0, 0, 31, 20, 15, 13, 12, 11, 10, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 };\r
-        private static readonly uint[] groupRadixValues = { 0, 0, 2147483648, 3486784401, 1073741824, 1220703125, 2176782336, 1977326743, 1073741824, 3486784401, 1000000000, 2357947691, 429981696, 815730721, 1475789056, 2562890625, 268435456, 410338673, 612220032, 893871739, 1280000000, 1801088541, 2494357888, 3404825447, 191102976, 244140625, 308915776, 387420489, 481890304, 594823321, 729000000, 887503681, 1073741824, 1291467969, 1544804416, 1838265625, 2176782336 };\r
-\r
-       public static ArgumentOutOfRangeException MakeArgumentOutOfRangeException(string paramName, object actualValue, string message) {\r
-               return new ArgumentOutOfRangeException(paramName, string.Format("{0} (actual value is '{1}')", message, actualValue));\r
-       }\r
-       \r
-        internal static string BigIntegerToString(uint[] d, int sign, int radix) {\r
-            if (radix < 2) {\r
-                   throw MakeArgumentOutOfRangeException("radix", radix, "radix must be >= 2");\r
-            }\r
-            if (radix > 36) {\r
-                throw MakeArgumentOutOfRangeException("radix", radix, "radix must be <= 36");\r
-            }\r
-\r
-            int dl = d.Length;\r
-            if (dl == 0) {\r
-                return "0";\r
-            }\r
-\r
-            List<uint> digitGroups = new List<uint>();\r
-\r
-            uint groupRadix = groupRadixValues[radix];\r
-            while (dl > 0) {\r
-                uint rem = div(d, ref dl, groupRadix);\r
-                digitGroups.Add(rem);\r
-            }\r
-\r
-            StringBuilder ret = new StringBuilder();\r
-            if (sign == -1) {\r
-                ret.Append("-");\r
-            }\r
-\r
-            int digitIndex = digitGroups.Count - 1;\r
-\r
-            char[] tmpDigits = new char[maxCharsPerDigit[radix]];\r
-\r
-            AppendRadix((uint)digitGroups[digitIndex--], (uint)radix, tmpDigits, ret, false);\r
-            while (digitIndex >= 0) {\r
-                AppendRadix((uint)digitGroups[digitIndex--], (uint)radix, tmpDigits, ret, true);\r
-            }\r
-            return ret.Length == 0 ? "0" : ret.ToString();\r
-        }\r
-\r
-        private static uint div(uint[] n, ref int nl, uint d) {\r
-            ulong rem = 0;\r
-            int i = nl;\r
-            bool seenNonZero = false;\r
-            while (--i >= 0) {\r
-                rem <<= BitsPerDigit;\r
-                rem |= n[i];\r
-                uint v = (uint)(rem / d);\r
-                n[i] = v;\r
-                if (v == 0) {\r
-                    if (!seenNonZero) nl--;\r
-                } else {\r
-                    seenNonZero = true;\r
-                }\r
-                rem %= d;\r
-            }\r
-            return (uint)rem;\r
-        }\r
-\r
-        private static void AppendRadix(uint rem, uint radix, char[] tmp, StringBuilder buf, bool leadingZeros) {\r
-            const string symbols = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";\r
-\r
-            int digits = tmp.Length;\r
-            int i = digits;\r
-            while (i > 0 && (leadingZeros || rem != 0)) {\r
-                uint digit = rem % radix;\r
-                rem /= radix;\r
-                tmp[--i] = symbols[(int)digit];\r
-            }\r
-            if (leadingZeros) buf.Append(tmp);\r
-            else buf.Append(tmp, i, digits - i);\r
-        }\r
-\r
-       public string ToString(int radix) {\r
-            return BigIntegerToString(copy(data), sign, radix);\r
-        }\r
-\r
-        public override int GetHashCode() {\r
-            // The Object.GetHashCode function needs to be consistent with the Object.Equals function.\r
-            // Languages that build on top of this may have a more flexible equality function and \r
-            // so may not be able to use this hash function directly.\r
-            // For example, Python allows BigInteger(10) == int32(10), so hashing a BigInt over the Int32\r
-            // domain should return the same value as a hash of the Int32.\r
-\r
-            // If this is in the int32 range, this hash function returns the integer.\r
-            if (data.Length == 0) {\r
-                return 0;\r
-            }\r
-\r
-            // Add up all uints. We want to incorporate all bits to get good hash distribution. \r
-            uint total = 0;\r
-            foreach (uint x in data) {\r
-                total = unchecked(total + x);\r
-            }\r
-\r
-            int hash = unchecked((int)total);\r
-\r
-            // The sign is not part of the data array, so explicitly incorporate that.\r
-            // This is also needed to ensure that hash(-x) == -x for int32.\r
-            if (IsNegative()) {\r
-                return unchecked(-hash);\r
-            } else {\r
-                return hash;\r
-            }\r
-        }\r
-\r
-        public override bool Equals(object obj) {\r
-            return Equals(obj as BigInteger);\r
-        }\r
-\r
-        public bool Equals(BigInteger other) {\r
-            if (object.ReferenceEquals(other, null)) return false;\r
-            return this == other;\r
-        }\r
-\r
-\r
-        public bool IsNegative() {\r
-            return sign < 0;\r
-        }\r
-\r
-        public bool IsZero() {\r
-            return sign == 0;\r
-        }\r
-\r
-        public bool IsPositive() {\r
-            return sign > 0;\r
-        }\r
-\r
-        private bool IsOdd() {\r
-            // must have the lowest-order bit set to 1\r
-            return (data != null && data.Length > 0 && ((data[0] & 1) != 0));\r
-        }\r
-\r
-\r
-        public double Log(Double newBase) {\r
-            if (IsNegative() || newBase == 1.0D || this == Zero || (newBase == 0.0D && this != One)) {\r
-                return Double.NaN;\r
-            } else if (newBase == Double.PositiveInfinity) {\r
-                return this == One ? 0.0D : Double.NaN;\r
-            }\r
-\r
-            int length = GetLength(data) - 1;\r
-            int bitCount = -1;\r
-            for (int curBit = 31; curBit >= 0; curBit--) {\r
-                if ((data[length] & (1 << curBit)) != 0) {\r
-                    bitCount = curBit + length * 32;\r
-                    break;\r
-                }\r
-            }\r
-\r
-            long bitlen = bitCount;\r
-            Double c = 0, d = 1;\r
-\r
-            BigInteger testBit = BigInteger.One;\r
-            long tempBitlen = bitlen;\r
-            while (tempBitlen > Int32.MaxValue) {\r
-                testBit = testBit << Int32.MaxValue;\r
-                tempBitlen -= Int32.MaxValue;\r
-            }\r
-            testBit = testBit << (int)tempBitlen;\r
-\r
-            for (long curbit = bitlen; curbit >= 0; --curbit) {\r
-                if ((this & testBit) != BigInteger.Zero)\r
-                    c += d;\r
-                d *= 0.5;\r
-                testBit = testBit >> 1;\r
-            }\r
-            return (System.Math.Log(c) + System.Math.Log(2) * bitlen) / System.Math.Log(newBase);\r
-        }\r
-\r
-        /// <summary>\r
-        /// Calculates the natural logarithm of the BigInteger.\r
-        /// </summary>\r
-        public double Log() {\r
-            return Log(System.Math.E);\r
-        }\r
-\r
-        /// <summary>\r
-        /// Calculates log base 10 of a BigInteger.\r
-        /// </summary>\r
-        public double Log10() {\r
-            return Log(10);\r
-        }\r
-\r
-        #region IComparable Members\r
-\r
-        public int CompareTo(object obj) {\r
-            if (obj == null) {\r
-                return 1;\r
-            }\r
-            BigInteger o = obj as BigInteger;\r
-            if (object.ReferenceEquals(o, null)) {\r
-                throw new ArgumentException("expected integer");\r
-            }\r
-            return Compare(this, o);\r
-        }\r
-\r
-        #endregion\r
-\r
-        #region IConvertible Members\r
-\r
-        public TypeCode GetTypeCode() {\r
-            return TypeCode.Object;\r
-        }\r
-\r
-        public bool ToBoolean(IFormatProvider provider) {\r
-            return this != Zero;\r
-        }\r
-\r
-        public byte ToByte(IFormatProvider provider) {\r
-            uint ret;\r
-            if (AsUInt32(out ret) && (ret & ~0xFF) == 0) {\r
-                return (byte)ret;\r
-            }\r
-            throw new OverflowException("big integer won't fit into byte");\r
-        }\r
-\r
-        /// <summary>\r
-        /// Return the value of this BigInteger as a little-endian twos-complement\r
-        /// byte array, using the fewest number of bytes possible. If the value is zero,\r
-        /// return an array of one byte whose element is 0x00.\r
-        /// </summary>\r
-        public byte[] ToByteArray() {\r
-            // We could probably make this more efficient by eliminating one of the passes.\r
-            // The current code does one pass for uint array -> byte array conversion,\r
-            // and then a another pass to remove unneeded bytes at the top of the array.\r
-            if (0 == sign) return new byte[] { 0 };\r
-\r
-            uint[] dwords;\r
-            byte highByte;\r
-\r
-            if (-1 == sign) {\r
-                dwords = (uint[])this.data.Clone();\r
-                makeTwosComplement(dwords);\r
-                highByte = 0xff;\r
-            } else {\r
-                dwords = this.data;\r
-                highByte = 0x00;\r
-            }\r
-\r
-            byte[] bytes = new byte[4 * dwords.Length];\r
-            int curByte = 0;\r
-            uint dword;\r
-            for (int i = 0; i < dwords.Length; i++) {\r
-                dword = dwords[i];\r
-                for (int j = 0; j < 4; j++) {\r
-                    bytes[curByte++] = (byte)(dword & 0xff);\r
-                    dword >>= 8;\r
-                }\r
-            }\r
-\r
-            // find highest significant byte\r
-            int msb;\r
-            for (msb = bytes.Length - 1; msb > 0; msb--) {\r
-                if (bytes[msb] != highByte) break;\r
-            }\r
-            // ensure high bit is 0 if positive, 1 if negative\r
-            bool needExtraByte = (bytes[msb] & 0x80) != (highByte & 0x80);\r
-\r
-            byte[] trimmedBytes = new byte[msb + 1 + (needExtraByte ? 1 : 0)];\r
-            Array.Copy(bytes, trimmedBytes, msb + 1);\r
-\r
-            if (needExtraByte) trimmedBytes[trimmedBytes.Length - 1] = highByte;\r
-\r
-            return trimmedBytes;\r
-        }\r
-\r
-        public char ToChar(IFormatProvider provider) {\r
-            int ret;\r
-            if (AsInt32(out ret) && (ret <= Char.MaxValue) && (ret >= Char.MinValue)) {\r
-                return (char)ret;\r
-            }\r
-            throw new OverflowException("big integer won't fit into char");\r
-        }\r
-\r
-        public DateTime ToDateTime(IFormatProvider provider) {\r
-            throw new NotImplementedException();\r
-        }\r
-\r
-        public decimal ToDecimal(IFormatProvider provider) {\r
-            decimal ret;\r
-            if (AsDecimal(out ret)) return ret;\r
-            throw new OverflowException("big integer won't fit into decimal");\r
-        }\r
-\r
-        public double ToDouble(IFormatProvider provider) {\r
-            return ToFloat64();\r
-        }\r
-\r
-        public short ToInt16(IFormatProvider provider) {\r
-            int ret;\r
-            if (AsInt32(out ret) && (ret <= short.MaxValue) && (ret >= short.MinValue)) {\r
-                return (short)ret;\r
-            }\r
-            throw new OverflowException("big integer won't fit into short");\r
-        }\r
-\r
-        public int ToInt32(IFormatProvider provider) {\r
-            int ret;\r
-            if (AsInt32(out ret)) {\r
-                return ret;\r
-            }\r
-            throw new OverflowException("big integer won't fit into int");\r
-        }\r
-\r
-        public long ToInt64(IFormatProvider provider) {\r
-            long ret;\r
-            if (AsInt64(out ret)) {\r
-                return ret;\r
-            }\r
-            throw new OverflowException("big integer won't fit into long");\r
-        }\r
-\r
-        [CLSCompliant(false)]\r
-        public sbyte ToSByte(IFormatProvider provider) {\r
-            int ret;\r
-            if (AsInt32(out ret) && (ret <= sbyte.MaxValue) && (ret >= sbyte.MinValue)) {\r
-                return (sbyte)ret;\r
-            }\r
-            throw new OverflowException("big integer won't fit into sbyte");\r
-        }\r
-\r
-        public float ToSingle(IFormatProvider provider) {\r
-            return checked((float)ToDouble(provider));\r
-        }\r
-\r
-        public string ToString(IFormatProvider provider) {\r
-            return ToString();\r
-        }\r
-\r
-        public object ToType(Type conversionType, IFormatProvider provider) {\r
-            if (conversionType == typeof(BigInteger)) {\r
-                return this;\r
-            }\r
-            throw new NotImplementedException();\r
-        }\r
-\r
-        [CLSCompliant(false)]\r
-        public ushort ToUInt16(IFormatProvider provider) {\r
-            uint ret;\r
-            if (AsUInt32(out ret) && ret <= ushort.MaxValue) {\r
-                return (ushort)ret;\r
-            }\r
-            throw new OverflowException("big integer won't fit into ushort");\r
-        }\r
-\r
-        [CLSCompliant(false)]\r
-        public uint ToUInt32(IFormatProvider provider) {\r
-            uint ret;\r
-            if (AsUInt32(out ret)) {\r
-                return ret;\r
-            }\r
-            throw new OverflowException("big integer won't fit into uint");\r
-        }\r
-\r
-        [CLSCompliant(false)]\r
-        public ulong ToUInt64(IFormatProvider provider) {\r
-            ulong ret;\r
-            if (AsUInt64(out ret)) {\r
-                return ret;\r
-            }\r
-            throw new OverflowException("big integer won't fit into ulong");\r
-        }\r
-\r
-        #endregion\r
-\r
-        #region IFormattable Members\r
-\r
-        string IFormattable.ToString(string format, IFormatProvider formatProvider) {\r
-            if (format == null) return this.ToString();\r
-\r
-            switch (format[0]) {\r
-                case 'd':\r
-                case 'D':\r
-                    if (format.Length > 1) {\r
-                        int precision = Convert.ToInt32(format.Substring(1), CultureInfo.InvariantCulture.NumberFormat);\r
-                        string baseStr = ToString(10);\r
-                        if (baseStr.Length < precision) {\r
-                            string additional = new String('0', precision - baseStr.Length);\r
-                            if (baseStr[0] != '-') {\r
-                                return additional + baseStr;\r
-                            } else {\r
-                                return "-" + additional + baseStr.Substring(1);\r
-                            }\r
-                        }\r
-                        return baseStr;\r
-                    }\r
-                    return ToString(10);\r
-                case 'x':\r
-                case 'X':\r
-                    StringBuilder res = new StringBuilder(ToString(16));\r
-                    if (format[0] == 'x') {\r
-                        for (int i = 0; i < res.Length; i++) {\r
-                            if (res[i] >= 'A' && res[i] <= 'F') {\r
-                                res[i] = Char.ToLower(res[i], CultureInfo.InvariantCulture);\r
-                            }\r
-                        }\r
-                    }\r
-\r
-                    if (format.Length > 1) {\r
-                        int precision = Convert.ToInt32(format.Substring(1), CultureInfo.InvariantCulture.NumberFormat);\r
-                        if (res.Length < precision) {\r
-                            string additional = new String('0', precision - res.Length);\r
-                            if (res[0] != '-') {\r
-                                res.Insert(0, additional);\r
-                            } else {\r
-                                res.Insert(1, additional);\r
-                            }\r
-                        }\r
-                    }\r
-\r
-                    return res.ToString();\r
-                default:\r
-                    throw new NotImplementedException("format not implemented");\r
-            }\r
-        }\r
-\r
-        #endregion        \r
-    }\r
-}\r
+//
+// System.Numerics.BigInteger
+//
+// Rodrigo Kumpera (rkumpera@novell.com)
+
+//
+// Copyright (C) 2010 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// A big chuck of code comes the DLR (as hosted in http://ironpython.codeplex.com), 
+// which has the following License:
+//
+/* ****************************************************************************
+ *
+ * Copyright (c) Microsoft Corporation. 
+ *
+ * This source code is subject to terms and conditions of the Microsoft Public License. A 
+ * copy of the license can be found in the License.html file at the root of this distribution. If 
+ * you cannot locate the  Microsoft Public License, please send an email to 
+ * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
+ * by the terms of the Microsoft Public License.
+ *
+ * You must not remove this notice, or any other, from this software.
+ *
+ *
+ * ***************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Text;
+using System.Threading;
+
+/*
+Optimization
+       Have proper popcount function for IsPowerOfTwo
+       Use unsafe ops to avoid bounds check
+       CoreAdd could avoid some resizes by checking for equal sized array that top overflow
+       For bitwise operators, hoist the conditionals out of their main loop
+       Optimize BitScanBackward
+       Use a carry variable to make shift opts do half the number of array ops.
+       Schoolbook multiply is O(n^2), use Karatsuba /Toom-3 for large numbers
+*/
+namespace System.Numerics {
+       public struct BigInteger : IComparable, IFormattable, IComparable<BigInteger>, IEquatable<BigInteger>
+       {
+               //LSB on [0]
+               readonly uint[] data;
+               readonly short sign;
+
+               static readonly uint[] ZERO = new uint [1];
+               static readonly uint[] ONE = new uint [1] { 1 };
+
+               BigInteger (short sign, uint[] data)
+               {
+                       this.sign = sign;
+                       this.data = data;
+               }
+
+               public BigInteger (int value)
+               {
+                       if (value == 0) {
+                               sign = 0;
+                               data = ZERO;
+                       } else if (value > 0) {
+                               sign = 1;
+                               data = new uint[] { (uint) value };
+                       } else {
+                               sign = -1;
+                               data = new uint[1] { (uint)-value };
+                       }
+               }
+
+               [CLSCompliantAttribute (false)]
+               public BigInteger (uint value)
+               {
+                       if (value == 0) {
+                               sign = 0;
+                               data = ZERO;
+                       } else {
+                               sign = 1;
+                               data = new uint [1] { value };
+                       }
+               }
+
+               public BigInteger (long value)
+               {
+                       if (value == 0) {
+                               sign = 0;
+                               data = ZERO;
+                       } else if (value > 0) {
+                               sign = 1;
+                               uint low = (uint)value;
+                               uint high = (uint)(value >> 32);
+
+                               data = new uint [high != 0 ? 2 : 1];
+                               data [0] = low;
+                               if (high != 0)
+                                       data [1] = high;
+                       } else {
+                               sign = -1;
+                               value = -value;
+                               uint low = (uint)value;
+                               uint high = (uint)((ulong)value >> 32);
+
+                               data = new uint [high != 0 ? 2 : 1];
+                               data [0] = low;
+                               if (high != 0)
+                                       data [1] = high;
+                       }                       
+               }
+
+               [CLSCompliantAttribute (false)]
+               public BigInteger (ulong value)
+               {
+                       if (value == 0) {
+                               sign = 0;
+                               data = ZERO;
+                       } else {
+                               sign = 1;
+                               uint low = (uint)value;
+                               uint high = (uint)(value >> 32);
+
+                               data = new uint [high != 0 ? 2 : 1];
+                               data [0] = low;
+                               if (high != 0)
+                                       data [1] = high;
+                       }
+               }
+
+
+               static bool Negative (byte[] v)
+               {
+                       return ((v[7] & 0x80) != 0);
+               }
+
+               static ushort Exponent (byte[] v)
+               {
+                       return (ushort)((((ushort)(v[7] & 0x7F)) << (ushort)4) | (((ushort)(v[6] & 0xF0)) >> 4));
+               }
+
+               static ulong Mantissa(byte[] v)
+               {
+                       uint i1 = ((uint)v[0] | ((uint)v[1] << 8) | ((uint)v[2] << 16) | ((uint)v[3] << 24));
+                       uint i2 = ((uint)v[4] | ((uint)v[5] << 8) | ((uint)(v[6] & 0xF) << 16));
+
+                       return (ulong)((ulong)i1 | ((ulong)i2 << 32));
+               }
+
+               const int bias = 1075;
+               public BigInteger (double value)
+               {
+                       if (double.IsNaN (value) || Double.IsInfinity (value))
+                               throw new OverflowException ();
+
+                       byte[] bytes = BitConverter.GetBytes (value);
+                       ulong mantissa = Mantissa (bytes);
+                       if (mantissa == 0) {
+                               // 1.0 * 2**exp, we have a power of 2
+                               int exponent = Exponent (bytes);
+                               if (exponent == 0) {
+                                       sign = 0;
+                                       data = ZERO;
+                                       return;
+                               }
+
+                               BigInteger res = Negative (bytes) ? MinusOne : One;
+                               res = res << (exponent - 0x3ff);
+                               this.sign = res.sign;
+                               this.data = res.data;
+                       } else {
+                               // 1.mantissa * 2**exp
+                               int exponent = Exponent(bytes);
+                               mantissa |= 0x10000000000000ul;
+                               BigInteger res = mantissa;
+                               res = exponent > bias ? res << (exponent - bias) : res >> (bias - exponent);
+
+                               this.sign = (short) (Negative (bytes) ? -1 : 1);
+                               this.data = res.data;
+                       }
+               }
+
+               public BigInteger (float value) : this ((double)value)
+               {
+               }
+
+               const Int32 DecimalScaleFactorMask = 0x00FF0000;
+               const Int32 DecimalSignMask = unchecked((Int32)0x80000000);
+
+               public BigInteger (decimal value)
+               {
+                       // First truncate to get scale to 0 and extract bits
+                       int[] bits = Decimal.GetBits(Decimal.Truncate(value));
+
+                       int size = 3;
+                       while (size > 0 && bits[size - 1] == 0) size--;
+
+                       if (size == 0) {
+                               sign = 0;
+                               data = ZERO;
+                               return;
+                       }
+
+                       sign = (short) ((bits [3] & DecimalSignMask) != 0 ? -1 : 1);
+
+                       data = new uint [size];
+                       data [0] = (uint)bits [0];
+                       if (size > 1)
+                               data [1] = (uint)bits [1];
+                       if (size > 2)
+                               data [2] = (uint)bits [2];
+               }
+
+               [CLSCompliantAttribute (false)]
+               public BigInteger (byte[] value)
+               {
+                       if (value == null)
+                               throw new ArgumentNullException ("value");
+
+                       int len = value.Length;
+
+                       if (len == 0 || (len == 1 && value [0] == 0)) {
+                               sign = 0;
+                               data = ZERO;
+                               return;
+                       }
+
+                       if ((value [len - 1] & 0x80) != 0)
+                               sign = -1;
+                       else
+                               sign = 1;
+
+                       if (sign == 1) {
+                               while (value [len - 1] == 0) {
+                                       if (--len == 0) {
+                                               sign = 0;
+                                               data = ZERO;
+                                               return;
+                                       }
+                               }
+
+                               int full_words, size;
+                               full_words = size = len / 4;
+                               if ((len & 0x3) != 0)
+                                       ++size;
+
+                               data = new uint [size];
+                               int j = 0;
+                               for (int i = 0; i < full_words; ++i) {
+                                       data [i] =      (uint)value [j++] |
+                                                               (uint)(value [j++] << 8) |
+                                                               (uint)(value [j++] << 16) |
+                                                               (uint)(value [j++] << 24);
+                               }
+                               size = len & 0x3;
+                               if (size > 0) {
+                                       int idx = data.Length - 1;
+                                       for (int i = 0; i < size; ++i)
+                                               data [idx] |= (uint)(value [j++] << (i * 8));
+                               }
+                       } else {
+                               int full_words, size;
+                               full_words = size = len / 4;
+                               if ((len & 0x3) != 0)
+                                       ++size;
+
+                               data = new uint [size];
+
+                               uint word, borrow = 1;
+                               ulong sub = 0;
+                               int j = 0;
+
+                               for (int i = 0; i < full_words; ++i) {
+                                       word =  (uint)value [j++] |
+                                                       (uint)(value [j++] << 8) |
+                                                       (uint)(value [j++] << 16) |
+                                                       (uint)(value [j++] << 24);
+
+                                       sub = (ulong)word - borrow;
+                                       word = (uint)sub;
+                                       borrow = (uint)(sub >> 32) & 0x1u;
+                                       data [i] = ~word;
+                               }
+                               size = len & 0x3;
+
+                               if (size > 0) {
+                                       word = 0;
+                                       uint store_mask = 0;
+                                       for (int i = 0; i < size; ++i) {
+                                               word |= (uint)(value [j++] << (i * 8));
+                                               store_mask = (store_mask << 8) | 0xFF;
+                                       }
+
+                                       sub = word - borrow;
+                                       word = (uint)sub;
+                                       borrow = (uint)(sub >> 32) & 0x1u;
+
+                                       data [data.Length - 1] = ~word & store_mask;
+                               }
+                               if (borrow != 0) //FIXME I believe this can't happen, can someone write a test for it?
+                                       throw new Exception ("non zero final carry");
+                       }
+
+               }
+
+               public bool IsEven {
+                       get { return sign == 0 || (data [0] & 0x1) == 0; }
+               }               
+
+               public bool IsOne {
+                       get { return sign == 1 && data.Length == 1 && data [0] == 1; }
+               }               
+
+
+               //Gem from Hacker's Delight
+               //Returns the number of bits set in @x
+               static int PopulationCount (uint x)
+               {
+                       x = x - ((x >> 1) & 0x55555555);
+                       x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
+                       x = (x + (x >> 4)) & 0x0F0F0F0F;
+                       x = x + (x >> 8);
+                       x = x + (x >> 16);
+                       return (int)(x & 0x0000003F);
+               }
+
+               public bool IsPowerOfTwo {
+                       get {
+                               bool foundBit = false;
+                               if (sign != 1)
+                                       return false;
+                               //This function is pop count == 1 for positive numbers
+                               for (int i = 0; i < data.Length; ++i) {
+                                       int p = PopulationCount (data [i]);
+                                       if (p > 0) {
+                                               if (p > 1 || foundBit)
+                                                       return false;
+                                               foundBit = true;
+                                       }
+                               }
+                               return foundBit;
+                       }
+               }               
+
+               public bool IsZero {
+                       get { return sign == 0; }
+               }               
+
+               public int Sign {
+                       get { return sign; }
+               }
+
+               public static BigInteger MinusOne {
+                       get { return new BigInteger (-1, ONE); }
+               }
+
+               public static BigInteger One {
+                       get { return new BigInteger (1, ONE); }
+               }
+
+               public static BigInteger Zero {
+                       get { return new BigInteger (0, ZERO); }
+               }
+
+               public static explicit operator int (BigInteger value)
+               {
+                       if (value.sign == 0)
+                               return 0;
+                       if (value.data.Length > 1)
+                               throw new OverflowException ();
+                       uint data = value.data [0];
+
+                       if (value.sign == 1) {
+                               if (data > (uint)int.MaxValue)
+                                       throw new OverflowException ();
+                               return (int)data;
+                       } else if (value.sign == -1) {
+                               if (data > 0x80000000u)
+                                       throw new OverflowException ();
+                               return -(int)data;
+                       }
+
+                       return 0;
+               }
+
+               [CLSCompliantAttribute (false)]
+               public static explicit operator uint (BigInteger value)
+               {
+                       if (value.sign == 0)
+                               return 0;
+                       if (value.data.Length > 1 || value.sign == -1)
+                               throw new OverflowException ();
+                       return value.data [0];
+               }
+
+               public static explicit operator short (BigInteger value)
+               {
+                       int val = (int)value;
+                       if (val < short.MinValue || val > short.MaxValue)
+                               throw new OverflowException ();
+                       return (short)val;
+               }
+
+               [CLSCompliantAttribute (false)]
+               public static explicit operator ushort (BigInteger value)
+               {
+                       uint val = (uint)value;
+                       if (val > ushort.MaxValue)
+                               throw new OverflowException ();
+                       return (ushort)val;
+               }
+
+               public static explicit operator byte (BigInteger value)
+               {
+                       uint val = (uint)value;
+                       if (val > byte.MaxValue)
+                               throw new OverflowException ();
+                       return (byte)val;
+               }
+
+               [CLSCompliantAttribute (false)]
+               public static explicit operator sbyte (BigInteger value)
+               {
+                       int val = (int)value;
+                       if (val < sbyte.MinValue || val > sbyte.MaxValue)
+                               throw new OverflowException ();
+                       return (sbyte)val;
+               }
+
+
+               public static explicit operator long (BigInteger value)
+               {
+                       if (value.sign == 0)
+                               return 0;
+
+                       if (value.data.Length > 2)
+                               throw new OverflowException ();
+
+                       uint low = value.data [0];
+
+                       if (value.data.Length == 1) {
+                               if (value.sign == 1)
+                                       return (long)low;
+                               long res = (long)low;
+                               return -res;
+                       }
+
+                       uint high = value.data [1];
+
+                       if (value.sign == 1) {
+                               if (high >= 0x80000000u)
+                                       throw new OverflowException ();
+                               return (((long)high) << 32) | low;
+                       }
+
+                       /*
+                       We cannot represent negative numbers smaller than long.MinValue.
+                       Those values are encoded into what look negative numbers, so negating
+                       them produces a positive value, that's why it's safe to check for that
+                       condition.
+
+                       long.MinValue works fine since it's bigint encoding looks like a negative
+                       number, but since long.MinValue == -long.MinValue, we're good.
+                       */
+
+                       long result = - ((((long)high) << 32) | (long)low);
+                       if (result > 0)
+                               throw new OverflowException ();
+                       return result;
+               }
+
+               [CLSCompliantAttribute (false)]
+               public static explicit operator ulong (BigInteger value)
+               {
+                       if (value.sign == 0)
+                               return 0;
+                       if (value.data.Length > 2 || value.sign == -1)
+                               throw new OverflowException ();
+
+                       uint low = value.data [0];
+                       if (value.data.Length == 1)
+                               return low;
+
+                       uint high = value.data [1];
+                       return (((ulong)high) << 32) | low;
+               }
+
+               public static explicit operator double (BigInteger value)
+               {
+                       //FIXME
+                       try {
+                   return double.Parse (value.ToString (),
+                   System.Globalization.CultureInfo.InvariantCulture.NumberFormat);
+                       } catch (OverflowException) {
+                               return value.sign == -1 ? double.NegativeInfinity : double.PositiveInfinity;
+                       }
+        }
+
+               public static explicit operator float (BigInteger value)
+               {
+                       //FIXME
+                       try {
+                               return float.Parse (value.ToString (),
+                               System.Globalization.CultureInfo.InvariantCulture.NumberFormat);
+                       } catch (OverflowException) {
+                               return value.sign == -1 ? float.NegativeInfinity : float.PositiveInfinity;
+                       }
+               }
+
+               public static explicit operator decimal (BigInteger value)
+               {
+                       if (value.sign == 0)
+                       return Decimal.Zero;
+
+                       uint[] data = value.data;
+                       if (data.Length > 3) 
+                               throw new OverflowException ();
+
+                       int lo = 0, mi = 0, hi = 0;
+                       if (data.Length > 2)
+                               hi = (Int32)data [2];
+                       if (data.Length > 1)
+                               mi = (Int32)data [1];
+                       if (data.Length > 0)
+                               lo = (Int32)data [0];
+
+                       return new Decimal(lo, mi, hi, value.sign < 0, 0);
+               }
+
+               public static implicit operator BigInteger (int value)
+               {
+                       return new BigInteger (value);
+               }
+
+               [CLSCompliantAttribute (false)]
+               public static implicit operator BigInteger (uint value)
+               {
+                       return new BigInteger (value);
+               }
+
+               public static implicit operator BigInteger (short value)
+               {
+                       return new BigInteger (value);
+               }
+
+               [CLSCompliantAttribute (false)]
+               public static implicit operator BigInteger (ushort value)
+               {
+                       return new BigInteger (value);
+               }
+
+               public static implicit operator BigInteger (byte value)
+               {
+                       return new BigInteger (value);
+               }
+
+               [CLSCompliantAttribute (false)]
+               public static implicit operator BigInteger (sbyte value)
+               {
+                       return new BigInteger (value);
+               }
+
+               public static implicit operator BigInteger (long value)
+               {
+                       return new BigInteger (value);
+               }
+
+               [CLSCompliantAttribute (false)]
+               public static implicit operator BigInteger (ulong value)
+               {
+                       return new BigInteger (value);
+               }
+
+               public static explicit operator BigInteger (double value)
+               {
+                       return new BigInteger (value);
+               }
+
+               public static explicit operator BigInteger (float value)
+               {
+                       return new BigInteger (value);
+               }
+
+               public static explicit operator BigInteger (decimal value)
+               {
+                       return new BigInteger (value);
+               }
+
+               public static BigInteger operator+ (BigInteger left, BigInteger right)
+               {
+                       if (left.sign == 0)
+                               return right;
+                       if (right.sign == 0)
+                               return left;
+
+                       if (left.sign == right.sign)
+                               return new BigInteger (left.sign, CoreAdd (left.data, right.data));
+
+                       int r = CoreCompare (left.data, right.data);
+
+                       if (r == 0)     
+                               return new BigInteger (0, ZERO);
+
+                       if (r > 0) //left > right
+                               return new BigInteger (left.sign, CoreSub (left.data, right.data));
+
+                       return new BigInteger (right.sign, CoreSub (right.data, left.data));
+               }
+
+               public static BigInteger operator- (BigInteger left, BigInteger right)
+               {
+                       if (right.sign == 0)
+                               return left;
+                       if (left.sign == 0)
+                               return new BigInteger ((short)-right.sign, right.data);
+
+                       if (left.sign == right.sign) {
+                               int r = CoreCompare (left.data, right.data);
+
+                               if (r == 0)     
+                                       return new BigInteger (0, ZERO);
+
+                               if (r > 0) //left > right
+                                       return new BigInteger (left.sign, CoreSub (left.data, right.data));
+
+                               return new BigInteger ((short)-right.sign, CoreSub (right.data, left.data));
+                       }
+
+                       return new BigInteger (left.sign, CoreAdd (left.data, right.data));
+               }
+
+               public static BigInteger operator* (BigInteger left, BigInteger right)
+               {
+                       if (left.sign == 0 || right.sign == 0)
+                               return new BigInteger (0, ZERO);
+
+                       if (left.data [0] == 1 && left.data.Length == 1) {
+                               if (left.sign == 1)
+                                       return right;
+                               return new BigInteger ((short)-right.sign, right.data);
+                       }
+
+                       if (right.data [0] == 1 && right.data.Length == 1) {
+                               if (right.sign == 1)
+                                       return left;
+                               return new BigInteger ((short)-left.sign, left.data);
+                       }
+
+                       uint[] a = left.data;
+                       uint[] b = right.data;
+
+                       uint[] res = new uint [a.Length + b.Length];
+
+            for (int i = 0; i < a.Length; ++i) {
+                uint ai = a [i];
+                int k = i;
+
+                ulong carry = 0;
+                for (int j = 0; j < b.Length; ++j) {
+                    carry = carry + ((ulong)ai) * b [j] + res [k];
+                    res[k++] = (uint)carry;
+                    carry >>= 32;
+                }
+
+                while (carry != 0) {
+                    carry += res [k];
+                    res[k++] = (uint)carry;
+                    carry >>= 32;
+                }
+            }
+
+                       int m;
+                       for (m = res.Length - 1; m >= 0 && res [m] == 0; --m) ;
+                       if (m < res.Length - 1)
+                               res = Resize (res, m + 1);
+
+                       return new BigInteger ((short)(left.sign * right.sign), res);
+               }
+
+               public static BigInteger operator/ (BigInteger dividend, BigInteger divisor)
+               {
+                       if (divisor.sign == 0)
+                               throw new DivideByZeroException ();
+
+                       if (dividend.sign == 0) 
+                               return dividend;
+
+                       uint[] quotient;
+                       uint[] remainder_value;
+
+                       DivModUnsigned (dividend.data, divisor.data, out quotient, out remainder_value);
+
+                       int i;
+                       for (i = quotient.Length - 1; i >= 0 && quotient [i] == 0; --i) ;
+                       if (i == -1)
+                               return new BigInteger (0, ZERO);
+                       if (i < quotient.Length - 1)
+                               quotient = Resize (quotient, i + 1);
+
+                       return new BigInteger ((short)(dividend.sign * divisor.sign), quotient);
+               }
+
+               public static BigInteger operator% (BigInteger dividend, BigInteger divisor)
+               {
+                       if (divisor.sign == 0)
+                               throw new DivideByZeroException ();
+
+                       if (dividend.sign == 0)
+                               return dividend;
+
+                       uint[] quotient;
+                       uint[] remainder_value;
+
+                       DivModUnsigned (dividend.data, divisor.data, out quotient, out remainder_value);
+
+                       int i;
+                       for (i = remainder_value.Length - 1; i >= 0 && remainder_value [i] == 0; --i) ;
+                       if (i == -1)
+                               return new BigInteger (0, ZERO);
+
+                       if (i < remainder_value.Length - 1)
+                               remainder_value = Resize (remainder_value, i + 1);
+                       return new BigInteger (dividend.sign, remainder_value);
+               }
+
+               public static BigInteger operator- (BigInteger value)
+               {
+                       if (value.sign == 0)
+                               return value;
+                       return new BigInteger ((short)-value.sign, value.data);
+               }
+
+               public static BigInteger operator+ (BigInteger value)
+               {
+                       return value;
+               }
+
+               public static BigInteger operator++ (BigInteger value)
+               {
+                       if (value.sign == 0)
+                               return One;
+
+                       short sign = value.sign;
+                       uint[] data = value.data;
+                       if (data.Length == 1) {
+                               if (sign == -1 && data [0] == 1)
+                                       return new BigInteger (0, ZERO);
+                               if (sign == 0)
+                                       return new BigInteger (1, ONE);
+                       }
+
+                       if (sign == -1)
+                               data = CoreSub (data, 1);
+                       else
+                               data = CoreAdd (data, 1);
+               
+                       return new BigInteger (sign, data);
+               }
+
+               public static BigInteger operator-- (BigInteger value)
+               {
+                       if (value.sign == 0)
+                               return MinusOne;
+
+                       short sign = value.sign;
+                       uint[] data = value.data;
+                       if (data.Length == 1) {
+                               if (sign == 1 && data [0] == 1)
+                                       return new BigInteger (0, ZERO);
+                               if (sign == 0)
+                                       return new BigInteger (-1, ONE);
+                       }
+
+                       if (sign == -1)
+                               data = CoreAdd (data, 1);
+                       else
+                               data = CoreSub (data, 1);
+               
+                       return new BigInteger (sign, data);
+               }
+
+               public static BigInteger operator& (BigInteger left, BigInteger right)
+               {
+                       if (left.sign == 0)
+                               return left;
+
+                       if (right.sign == 0)
+                               return right;
+
+                       uint[] a = left.data;
+                       uint[] b = right.data;
+                       int ls = left.sign;
+                       int rs = right.sign;
+
+                       bool neg_res = (ls == rs) && (ls == -1);
+
+                       uint[] result = new uint [Math.Max (a.Length, b.Length)];
+
+                       ulong ac = 1, bc = 1, borrow = 1;
+
+                       int i;
+                       for (i = 0; i < result.Length; ++i) {
+                               uint va = 0;
+                               if (i < a.Length)
+                                       va = a [i];
+                               if (ls == -1) {
+                                       ac = ~va + ac;
+                                       va = (uint)ac;
+                                       ac = (uint)(ac >> 32);
+                               }
+
+                               uint vb = 0;
+                               if (i < b.Length)
+                                       vb = b [i];
+                               if (rs == -1) {
+                                       bc = ~vb + bc;
+                                       vb = (uint)bc;
+                                       bc = (uint)(bc >> 32);
+                               }
+
+                               uint word = va & vb;
+
+                               if (neg_res) {
+                                       borrow = word - borrow;
+                                       word = ~(uint)borrow;
+                                       borrow = (uint)(borrow >> 32) & 0x1u;
+                               }
+
+                               result [i] = word;
+                       }
+
+                       for (i = result.Length - 1; i >= 0 && result [i] == 0; --i) ;
+                       if (i == -1)
+                               return new BigInteger (0, ZERO);
+       
+                       if (i < result.Length - 1)
+                               result = Resize (result, i + 1);
+
+                       return new BigInteger (neg_res ? (short)-1 : (short)1, result);
+               }
+
+               public static BigInteger operator| (BigInteger left, BigInteger right)
+               {
+                       if (left.sign == 0)
+                               return right;
+
+                       if (right.sign == 0)
+                               return left;
+
+                       uint[] a = left.data;
+                       uint[] b = right.data;
+                       int ls = left.sign;
+                       int rs = right.sign;
+
+                       bool neg_res = (ls == -1) || (rs == -1);
+
+                       uint[] result = new uint [Math.Max (a.Length, b.Length)];
+
+                       ulong ac = 1, bc = 1, borrow = 1;
+
+                       int i;
+                       for (i = 0; i < result.Length; ++i) {
+                               uint va = 0;
+                               if (i < a.Length)
+                                       va = a [i];
+                               if (ls == -1) {
+                                       ac = ~va + ac;
+                                       va = (uint)ac;
+                                       ac = (uint)(ac >> 32);
+                               }
+
+                               uint vb = 0;
+                               if (i < b.Length)
+                                       vb = b [i];
+                               if (rs == -1) {
+                                       bc = ~vb + bc;
+                                       vb = (uint)bc;
+                                       bc = (uint)(bc >> 32);
+                               }
+
+                               uint word = va | vb;
+
+                               if (neg_res) {
+                                       borrow = word - borrow;
+                                       word = ~(uint)borrow;
+                                       borrow = (uint)(borrow >> 32) & 0x1u;
+                               }
+
+                               result [i] = word;
+                       }
+
+                       for (i = result.Length - 1; i >= 0 && result [i] == 0; --i) ;
+                       if (i == -1)
+                               return new BigInteger (0, ZERO);
+       
+                       if (i < result.Length - 1)
+                               result = Resize (result, i + 1);
+
+                       return new BigInteger (neg_res ? (short)-1 : (short)1, result);
+               }
+
+               public static BigInteger operator^ (BigInteger left, BigInteger right)
+               {
+                       if (left.sign == 0)
+                               return right;
+
+                       if (right.sign == 0)
+                               return left;
+
+                       uint[] a = left.data;
+                       uint[] b = right.data;
+                       int ls = left.sign;
+                       int rs = right.sign;
+
+                       bool neg_res = (ls == -1) ^ (rs == -1);
+
+                       uint[] result = new uint [Math.Max (a.Length, b.Length)];
+
+                       ulong ac = 1, bc = 1, borrow = 1;
+
+                       int i;
+                       for (i = 0; i < result.Length; ++i) {
+                               uint va = 0;
+                               if (i < a.Length)
+                                       va = a [i];
+                               if (ls == -1) {
+                                       ac = ~va + ac;
+                                       va = (uint)ac;
+                                       ac = (uint)(ac >> 32);
+                               }
+
+                               uint vb = 0;
+                               if (i < b.Length)
+                                       vb = b [i];
+                               if (rs == -1) {
+                                       bc = ~vb + bc;
+                                       vb = (uint)bc;
+                                       bc = (uint)(bc >> 32);
+                               }
+
+                               uint word = va ^ vb;
+
+                               if (neg_res) {
+                                       borrow = word - borrow;
+                                       word = ~(uint)borrow;
+                                       borrow = (uint)(borrow >> 32) & 0x1u;
+                               }
+
+                               result [i] = word;
+                       }
+
+                       for (i = result.Length - 1; i >= 0 && result [i] == 0; --i) ;
+                       if (i == -1)
+                               return new BigInteger (0, ZERO);
+       
+                       if (i < result.Length - 1)
+                               result = Resize (result, i + 1);
+
+                       return new BigInteger (neg_res ? (short)-1 : (short)1, result);
+               }
+
+               public static BigInteger operator~ (BigInteger value)
+               {
+                       if (value.sign == 0)
+                               return new BigInteger (-1, ONE);
+
+                       uint[] data = value.data;
+                       int sign = value.sign;
+
+                       bool neg_res = sign == 1;
+
+                       uint[] result = new uint [data.Length];
+
+                       ulong carry = 1, borrow = 1;
+
+                       int i;
+                       for (i = 0; i < result.Length; ++i) {
+                               uint word = data [i];
+                               if (sign == -1) {
+                                       carry = ~word + carry;
+                                       word = (uint)carry;
+                                       carry = (uint)(carry >> 32);
+                               }
+
+                               word = ~word;
+
+                               if (neg_res) {
+                                       borrow = word - borrow;
+                                       word = ~(uint)borrow;
+                                       borrow = (uint)(borrow >> 32) & 0x1u;
+                               }
+
+                               result [i] = word;
+                       }
+
+                       for (i = result.Length - 1; i >= 0 && result [i] == 0; --i) ;
+                       if (i == -1)
+                               return new BigInteger (0, ZERO);
+       
+                       if (i < result.Length - 1)
+                               result = Resize (result, i + 1);
+
+                       return new BigInteger (neg_res ? (short)-1 : (short)1, result);
+               }
+
+               //returns the 0-based index of the most significant set bit
+               //returns 0 if no bit is set, so extra care when using it
+               static int BitScanBackward (uint word)
+               {
+                       for (int i = 31; i >= 0; --i) {
+                               uint mask = 1u << i;
+                               if ((word & mask) == mask)
+                                       return i;
+                       }
+                       return 0;
+               }
+
+               public static BigInteger operator<< (BigInteger value, int shift)
+               {
+                       if (shift == 0 || value.sign == 0)
+                               return value;
+                       if (shift < 0)
+                               return value >> -shift;
+
+                       uint[] data = value.data;
+                       int sign = value.sign;
+
+                       int topMostIdx = BitScanBackward (data [data.Length - 1]);
+                       int bits = shift - (31 - topMostIdx);
+                       int extra_words = (bits >> 5) + ((bits & 0x1F) != 0 ? 1 : 0);
+
+                       uint[] res = new uint [data.Length + extra_words];
+
+                       int idx_shift = shift >> 5;
+                       int bit_shift = shift & 0x1F;
+                       int carry_shift = 32 - bit_shift;
+
+                       if (carry_shift == 32) {
+                               for (int i = 0; i < data.Length; ++i) {
+                                       uint word = data [i];
+                                       res [i + idx_shift] |= word << bit_shift;
+                               }
+                       } else {
+                               for (int i = 0; i < data.Length; ++i) {
+                                       uint word = data [i];
+                                       res [i + idx_shift] |= word << bit_shift;
+                                       if (i + idx_shift + 1 < res.Length)
+                                               res [i + idx_shift + 1] = word >> carry_shift;
+                               }
+                       }
+
+                       return new BigInteger ((short)sign, res);
+               }
+
+               public static BigInteger operator>> (BigInteger value, int shift)
+               {
+                       if (shift == 0 || value.sign == 0)
+                               return value;
+                       if (shift < 0)
+                               return value << -shift;
+
+                       uint[] data = value.data;
+                       int sign = value.sign;
+
+                       int topMostIdx = BitScanBackward (data [data.Length - 1]);
+                       int idx_shift = shift >> 5;
+                       int bit_shift = shift & 0x1F;
+
+                       int extra_words = idx_shift;
+                       if (bit_shift > topMostIdx)
+                               ++extra_words;
+                       int size = data.Length - extra_words;
+
+                       if (size <= 0) {
+                               if (sign == 1)
+                                       return new BigInteger (0, ZERO);
+                               return new BigInteger (-1, ONE);
+                       }
+
+                       uint[] res = new uint [size];
+                       int carry_shift = 32 - bit_shift;
+
+                       if (carry_shift == 32) {
+                               for (int i = data.Length - 1; i >= idx_shift; --i) {
+                                       uint word = data [i];
+
+                                       if (i - idx_shift < res.Length)
+                                               res [i - idx_shift] |= word >> bit_shift;
+                               }
+                       } else {
+                               for (int i = data.Length - 1; i >= idx_shift; --i) {
+                                       uint word = data [i];
+
+                                       if (i - idx_shift < res.Length)
+                                               res [i - idx_shift] |= word >> bit_shift;
+                                       if (i - idx_shift - 1 >= 0)
+                                               res [i - idx_shift - 1] = word << carry_shift;
+                               }
+
+                       }
+
+                       //Round down instead of toward zero
+                       if (sign == -1) {
+                               for (int i = 0; i < idx_shift; i++) {
+                                       if (data [i] != 0u) {
+                                               var tmp = new BigInteger ((short)sign, res);
+                                               --tmp;
+                                               return tmp;
+                                       }
+                               }
+                               if (bit_shift > 0 && (data [idx_shift] << carry_shift) != 0u) {
+                                       var tmp = new BigInteger ((short)sign, res);
+                                       --tmp;
+                                       return tmp;
+                               }
+                       }
+                       return new BigInteger ((short)sign, res);
+               }
+
+               public static bool operator< (BigInteger left, BigInteger right)
+               {
+                       return Compare (left, right) < 0;
+               }
+
+               public static bool operator< (BigInteger left, long right)
+               {
+                       return left.CompareTo (right) < 0;
+               }
+
+
+               public static bool operator< (long left, BigInteger right)
+               {
+                       return right.CompareTo (left) > 0;
+               }
+
+
+               [CLSCompliantAttribute (false)]
+               public static bool operator< (BigInteger left, ulong right)
+               {
+                       return left.CompareTo (right) < 0;
+               }
+
+               [CLSCompliantAttribute (false)]
+               public static bool operator< (ulong left, BigInteger right)
+               {
+                       return right.CompareTo (left) > 0;
+               }
+
+               public static bool operator<= (BigInteger left, BigInteger right)
+               {
+                       return Compare (left, right) <= 0;
+               }
+
+               public static bool operator<= (BigInteger left, long right)
+               {
+                       return left.CompareTo (right) <= 0;
+               }
+
+               public static bool operator<= (long left, BigInteger right)
+               {
+                       return right.CompareTo (left) >= 0;
+               }
+
+               [CLSCompliantAttribute (false)]
+               public static bool operator<= (BigInteger left, ulong right)
+               {
+                       return left.CompareTo (right) <= 0;
+               }
+
+               [CLSCompliantAttribute (false)]
+               public static bool operator<= (ulong left, BigInteger right)
+               {
+                       return right.CompareTo (left) >= 0;
+               }
+
+               public static bool operator> (BigInteger left, BigInteger right)
+               {
+                       return Compare (left, right) > 0;
+               }
+
+               public static bool operator> (BigInteger left, long right)
+               {
+                       return left.CompareTo (right) > 0;
+               }
+
+               public static bool operator> (long left, BigInteger right)
+               {
+                       return right.CompareTo (left) < 0;
+               }
+
+               [CLSCompliantAttribute (false)]
+               public static bool operator> (BigInteger left, ulong right)
+               {
+                       return left.CompareTo (right) > 0;
+               }
+
+               [CLSCompliantAttribute (false)]
+               public static bool operator> (ulong left, BigInteger right)
+               {
+                       return right.CompareTo (left) < 0;
+               }
+
+               public static bool operator>= (BigInteger left, BigInteger right)
+               {
+                       return Compare (left, right) >= 0;
+               }
+
+               public static bool operator>= (BigInteger left, long right)
+               {
+                       return left.CompareTo (right) >= 0;
+               }
+
+               public static bool operator>= (long left, BigInteger right)
+               {
+                       return right.CompareTo (left) <= 0;
+               }
+
+               [CLSCompliantAttribute (false)]
+               public static bool operator>= (BigInteger left, ulong right)
+               {
+                       return left.CompareTo (right) >= 0;
+               }
+
+               [CLSCompliantAttribute (false)]
+               public static bool operator>= (ulong left, BigInteger right)
+               {
+                       return right.CompareTo (left) <= 0;
+               }
+
+               public static bool operator== (BigInteger left, BigInteger right)
+               {
+                       return Compare (left, right) == 0;
+               }
+
+               public static bool operator== (BigInteger left, long right)
+               {
+                       return left.CompareTo (right) == 0;
+               }
+
+               public static bool operator== (long left, BigInteger right)
+               {
+                       return right.CompareTo (left) == 0;
+               }
+
+               [CLSCompliantAttribute (false)]
+               public static bool operator== (BigInteger left, ulong right)
+               {
+                       return left.CompareTo (right) == 0;
+               }
+
+               [CLSCompliantAttribute (false)]
+               public static bool operator== (ulong left, BigInteger right)
+               {
+                       return right.CompareTo (left) == 0;
+               }
+
+               public static bool operator!= (BigInteger left, BigInteger right)
+               {
+                       return Compare (left, right) != 0;
+               }
+
+               public static bool operator!= (BigInteger left, long right)
+               {
+                       return left.CompareTo (right) != 0;
+               }
+
+               public static bool operator!= (long left, BigInteger right)
+               {
+                       return right.CompareTo (left) != 0;
+               }
+
+               [CLSCompliantAttribute (false)]
+               public static bool operator!= (BigInteger left, ulong right)
+               {
+                       return left.CompareTo (right) != 0;
+               }
+
+               [CLSCompliantAttribute (false)]
+               public static bool operator!= (ulong left, BigInteger right)
+               {
+                       return right.CompareTo (left) != 0;
+               }
+
+               public override bool Equals (object obj)
+               {
+                       if (!(obj is BigInteger))
+                               return false;
+                       return Equals ((BigInteger)obj);
+               }
+
+               public bool Equals (BigInteger other)
+               {
+                       if (sign != other.sign)
+                               return false;
+
+                       int alen = data != null ? data.Length : 0;
+                       int blen = other.data != null ? other.data.Length : 0;
+
+                       if (alen != blen)
+                               return false;
+                       for (int i = 0; i < alen; ++i) {
+                               if (data [i] != other.data [i])
+                                       return false;
+                       }
+                       return true;
+               }
+
+               public bool Equals (long other)
+               {
+                       return CompareTo (other) == 0;
+               }
+
+               public override string ToString ()
+               {
+                       return ToString (10, null);
+               }
+
+               string ToStringWithPadding (string format, uint radix, IFormatProvider provider)
+               {
+                       if (format.Length > 1) {
+                               int precision = Convert.ToInt32(format.Substring (1), CultureInfo.InvariantCulture.NumberFormat);
+                               string baseStr = ToString (radix, provider);
+                               if (baseStr.Length < precision) {
+                                       string additional = new String ('0', precision - baseStr.Length);
+                                       if (baseStr[0] != '-') {
+                                               return additional + baseStr;
+                                       } else {
+                                                       return "-" + additional + baseStr.Substring (1);
+                                       }
+                               }
+                               return baseStr;
+                       }
+                       return ToString (radix, provider);
+               }
+
+               public string ToString (string format)
+               {
+                       return ToString (format, null);
+               }
+
+               public string ToString (IFormatProvider provider)
+               {
+                       return ToString (null, provider);
+               }
+
+
+               public string ToString (string format, IFormatProvider provider)
+               {
+                       if (format == null || format == "")
+                               return ToString (10, provider);
+
+                       switch (format[0]) {
+                       case 'd':
+                       case 'D':
+                       case 'g':
+                       case 'G':
+                       case 'r':
+                       case 'R':
+                               return ToStringWithPadding (format, 10, provider);
+                       case 'x':
+                       case 'X':
+                               return ToStringWithPadding (format, 16, null);
+                       default:
+                               throw new FormatException (string.Format ("format '{0}' not implemented", format));
+                       }
+               }
+
+               static uint[] MakeTwoComplement (uint[] v)
+               {
+                       uint[] res = new uint [v.Length];
+
+                       ulong carry = 1;
+                       for (int i = 0; i < v.Length; ++i) {
+                               uint word = v [i];
+                               carry = (ulong)~word + carry;
+                               word = (uint)carry;
+                               carry = (uint)(carry >> 32);
+                               res [i] = word;
+                       }
+
+                       uint last = res [res.Length - 1];
+                       int idx = FirstNonFFByte (last);
+                       uint mask = 0xFF;
+                       for (int i = 1; i < idx; ++i)
+                               mask = (mask << 8) | 0xFF;
+
+                       res [res.Length - 1] = last & mask;
+                       return res;
+               }
+
+               string ToString (uint radix, IFormatProvider provider)
+               {
+                       const string characterSet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+                       if (characterSet.Length < radix)
+                               throw new ArgumentException ("charSet length less than radix", "characterSet");
+                       if (radix == 1)
+                               throw new ArgumentException ("There is no such thing as radix one notation", "radix");
+
+                       if (sign == 0)
+                               return "0";
+                       if (data.Length == 1 && data [0] == 1)
+                               return sign == 1 ? "1" : "-1";
+
+                       List<char> digits = new List<char> (1 + data.Length * 3 / 10);
+
+                       BigInteger a;
+                       if (sign == 1)
+                               a = this;
+                       else {
+                               uint[] dt = data;
+                               if (radix > 10)
+                                       dt = MakeTwoComplement (dt);
+                               a = new BigInteger (1, dt);
+                       }               
+
+                       while (a != 0) {
+                               BigInteger rem;
+                               a = DivRem (a, radix, out rem);
+                               digits.Add (characterSet [(int) rem]);
+                       }
+
+                       if (sign == -1 && radix == 10) {
+                               NumberFormatInfo info = null;
+                               if (provider != null)
+                                       info = provider.GetFormat (typeof (NumberFormatInfo)) as NumberFormatInfo;
+                               if (info != null) {
+                                       string str = info.NegativeSign;
+                                       for (int i = str.Length - 1; i >= 0; --i)
+                                               digits.Add (str [i]);
+                               } else {
+                                       digits.Add ('-');
+                               }
+                       }
+
+                       char last = digits [digits.Count - 1];
+                       if (sign == 1 && radix > 10 && (last < '0' || last > '9'))
+                               digits.Add ('0');
+               
+                       digits.Reverse ();
+
+                       return new String (digits.ToArray ());
+               }
+
+               public static BigInteger Parse (string value)
+               {
+                       Exception ex;
+                       BigInteger result;
+
+                       if (!Parse (value, false, out result, out ex))
+                               throw ex;
+                       return result;
+               }
+               
+               public static bool TryParse (string value, out BigInteger result)
+               {
+                       Exception ex;
+                       return Parse (value, true, out result, out ex);
+               }
+
+               public static BigInteger Parse (string value, NumberStyles style)
+               {
+                       return Parse (value, style, null);
+               }
+
+               public static BigInteger Parse (string value, IFormatProvider provider)
+               {
+                       return Parse (value, NumberStyles.Integer, provider);
+               }
+
+               public static BigInteger Parse (
+                       string value, NumberStyles style, IFormatProvider provider)
+               {
+                       Exception exc;
+                       BigInteger res;
+
+                       if (!Parse (value, style, provider, false, out res, out exc))
+                               throw exc;
+
+                       return res;
+               }
+
+               public static bool TryParse (
+                       string value, NumberStyles style, IFormatProvider provider,
+                       out BigInteger result)
+               {
+                       Exception exc;
+                       if (!Parse (value, style, provider, true, out result, out exc)) {
+                               result = Zero;
+                               return false;
+                       }
+
+                       return true;
+               }
+
+               internal static bool Parse (string s, NumberStyles style, IFormatProvider fp, bool tryParse, out BigInteger result, out Exception exc)
+               {
+                       result = Zero;
+                       exc = null;
+
+                       if (s == null) {
+                               if (!tryParse)
+                                       exc = new ArgumentNullException ("s");
+                               return false;
+                       }
+
+                       if (s.Length == 0) {
+                               if (!tryParse)
+                                       exc = GetFormatException ();
+                               return false;
+                       }
+
+                       NumberFormatInfo nfi = null;
+                       if (fp != null) {
+                               Type typeNFI = typeof(System.Globalization.NumberFormatInfo);
+                               nfi = (NumberFormatInfo)fp.GetFormat (typeNFI);
+                       }
+                       if (nfi == null)
+                               nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
+
+                       if (!CheckStyle (style, tryParse, ref exc))
+                               return false;
+
+                       bool AllowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0;
+                       bool AllowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0;
+                       bool AllowThousands = (style & NumberStyles.AllowThousands) != 0;
+                       bool AllowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0;
+                       bool AllowParentheses = (style & NumberStyles.AllowParentheses) != 0;
+                       bool AllowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0;
+                       bool AllowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0;
+                       bool AllowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0;
+                       bool AllowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0;
+                       bool AllowExponent = (style & NumberStyles.AllowExponent) != 0;
+
+                       int pos = 0;
+
+                       if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
+                               return false;
+
+                       bool foundOpenParentheses = false;
+                       bool negative = false;
+                       bool foundSign = false;
+                       bool foundCurrency = false;
+
+                       // Pre-number stuff
+                       if (AllowParentheses && s [pos] == '(') {
+                               foundOpenParentheses = true;
+                               foundSign = true;
+                               negative = true; // MS always make the number negative when there parentheses
+                               // even when NumberFormatInfo.NumberNegativePattern != 0!!!
+                               pos++;
+                               if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
+                                       return false;
+
+                               if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign) {
+                                       if (!tryParse)
+                                               exc = GetFormatException ();
+                                       return false;
+                               }
+                               
+                               if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign) {
+                                       if (!tryParse)
+                                               exc = GetFormatException ();
+                                       return false;
+                               }
+                       }
+
+                       if (AllowLeadingSign && !foundSign) {
+                               // Sign + Currency
+                               FindSign (ref pos, s, nfi, ref foundSign, ref negative);
+                               if (foundSign) {
+                                       if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
+                                               return false;
+                                       if (AllowCurrencySymbol) {
+                                               FindCurrency (ref pos, s, nfi,
+                                                             ref foundCurrency);
+                                               if (foundCurrency && AllowLeadingWhite &&
+                                                       !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
+                                                       return false;
+                                       }
+                               }
+                       }
+                       
+                       if (AllowCurrencySymbol && !foundCurrency) {
+                               // Currency + sign
+                               FindCurrency (ref pos, s, nfi, ref foundCurrency);
+                               if (foundCurrency) {
+                                       if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
+                                               return false;
+                                       if (foundCurrency) {
+                                               if (!foundSign && AllowLeadingSign) {
+                                                       FindSign (ref pos, s, nfi, ref foundSign,
+                                                                 ref negative);
+                                                       if (foundSign && AllowLeadingWhite &&
+                                                               !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
+                                                               return false;
+                                               }
+                                       }
+                               }
+                       }
+
+                       BigInteger number = Zero;
+                       int nDigits = 0;
+                       int decimalPointPos = -1;
+                       byte digitValue;
+                       char hexDigit;
+                       bool firstHexDigit = true;
+
+                       // Number stuff
+                       while (pos < s.Length) {
+
+                               if (!ValidDigit (s [pos], AllowHexSpecifier)) {
+                                       if (AllowThousands &&
+                                               (FindOther (ref pos, s, nfi.NumberGroupSeparator)
+                                               || FindOther (ref pos, s, nfi.CurrencyGroupSeparator)))
+                                               continue;
+
+                                       if (AllowDecimalPoint && decimalPointPos < 0 &&
+                                               (FindOther (ref pos, s, nfi.NumberDecimalSeparator)
+                                               || FindOther (ref pos, s, nfi.CurrencyDecimalSeparator))) {
+                                               decimalPointPos = nDigits;
+                                               continue;
+                                       }
+
+                                       break;
+                               }
+
+                               nDigits++;
+
+                               if (AllowHexSpecifier) {
+                                       hexDigit = s [pos++];
+                                       if (Char.IsDigit (hexDigit))
+                                               digitValue = (byte)(hexDigit - '0');
+                                       else if (Char.IsLower (hexDigit))
+                                               digitValue = (byte)(hexDigit - 'a' + 10);
+                                       else
+                                               digitValue = (byte)(hexDigit - 'A' + 10);
+
+                                       if (firstHexDigit && (byte)digitValue >= 8)
+                                               negative = true;
+
+                                       number = number * 16 + digitValue;
+                                       firstHexDigit = false;
+                                       continue;
+                               }
+
+                               number = number * 10 + (byte)(s [pos++] - '0');
+                       }
+
+                       // Post number stuff
+                       if (nDigits == 0) {
+                               if (!tryParse)
+                                       exc = GetFormatException ();
+                               return false;
+                       }
+
+                       //signed hex value
+                       if (AllowHexSpecifier && negative) {
+                               //number = 123456;
+                               BigInteger mask = BigInteger.Pow(16, nDigits) - 1;
+                               number = (number ^ mask) + 1;
+                       }
+
+                       int exponent = 0;
+                       if (AllowExponent)
+                               if (FindExponent (ref pos, s, ref exponent, tryParse, ref exc) && exc != null)
+                                       return false;
+
+                       if (AllowTrailingSign && !foundSign) {
+                               // Sign + Currency
+                               FindSign (ref pos, s, nfi, ref foundSign, ref negative);
+                               if (foundSign && pos < s.Length) {
+                                       if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
+                                               return false;
+                               }
+                       }
+                       
+                       if (AllowCurrencySymbol && !foundCurrency) {
+                               if (AllowTrailingWhite && pos < s.Length && !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
+                                       return false;
+                               
+                               // Currency + sign
+                               FindCurrency (ref pos, s, nfi, ref foundCurrency);
+                               if (foundCurrency  && pos < s.Length) {
+                                       if (AllowTrailingWhite  && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
+                                               return false;
+                                       if (!foundSign && AllowTrailingSign)
+                                               FindSign (ref pos, s, nfi, ref foundSign,
+                                                         ref negative);
+                               }
+                       }
+                       
+                       if (AllowTrailingWhite && pos < s.Length && !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
+                               return false;
+
+                       if (foundOpenParentheses) {
+                               if (pos >= s.Length || s [pos++] != ')') {
+                                       if (!tryParse)
+                                               exc = GetFormatException ();
+                                       return false;
+                               }
+                               if (AllowTrailingWhite && pos < s.Length && !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
+                                       return false;
+                       }
+
+                       if (pos < s.Length && s [pos] != '\u0000') {
+                               if (!tryParse)
+                                       exc = GetFormatException ();
+                               return false;
+                       }
+
+                       if (decimalPointPos >= 0)
+                               exponent = exponent - nDigits + decimalPointPos;
+                       
+                       if (exponent < 0) {
+                               //
+                               // Any non-zero values after decimal point are not allowed
+                               //
+                               BigInteger remainder;
+                               number = BigInteger.DivRem(number, BigInteger.Pow(10, -exponent), out remainder);
+
+                               if (!remainder.IsZero) {
+                                       if (!tryParse)
+                                               exc = new OverflowException ("Value too large or too small. exp="+exponent+" rem = " + remainder + " pow = " + BigInteger.Pow(10, -exponent));
+                                       return false;
+                               }
+                       } else if (exponent > 0) {
+                               number = BigInteger.Pow(10, exponent) * number;
+                       }
+
+                       if (number.sign == 0)
+                               result = number;
+                       else if (negative)
+                               result = new BigInteger (-1, number.data);
+                       else
+                               result = new BigInteger (1, number.data);
+
+                       return true;
+               }
+
+               internal static bool CheckStyle (NumberStyles style, bool tryParse, ref Exception exc)
+               {
+                       if ((style & NumberStyles.AllowHexSpecifier) != 0) {
+                               NumberStyles ne = style ^ NumberStyles.AllowHexSpecifier;
+                               if ((ne & NumberStyles.AllowLeadingWhite) != 0)
+                                       ne ^= NumberStyles.AllowLeadingWhite;
+                               if ((ne & NumberStyles.AllowTrailingWhite) != 0)
+                                       ne ^= NumberStyles.AllowTrailingWhite;
+                               if (ne != 0) {
+                                       if (!tryParse)
+                                               exc = new ArgumentException (
+                                                       "With AllowHexSpecifier only " + 
+                                                       "AllowLeadingWhite and AllowTrailingWhite " + 
+                                                       "are permitted.");
+                                       return false;
+                               }
+                       } else if ((uint) style > (uint) NumberStyles.Any){
+                               if (!tryParse)
+                                       exc = new ArgumentException ("Not a valid number style");
+                               return false;
+                       }
+
+                       return true;
+               }
+               
+               internal static bool JumpOverWhite (ref int pos, string s, bool reportError, bool tryParse, ref Exception exc)
+               {
+                       while (pos < s.Length && Char.IsWhiteSpace (s [pos]))
+                               pos++;
+
+                       if (reportError && pos >= s.Length) {
+                               if (!tryParse)
+                                       exc = GetFormatException ();
+                               return false;
+                       }
+
+                       return true;
+               }
+
+               internal static void FindSign (ref int pos, string s, NumberFormatInfo nfi, 
+                                     ref bool foundSign, ref bool negative)
+               {
+                       if ((pos + nfi.NegativeSign.Length) <= s.Length &&
+                           string.CompareOrdinal(s, pos, nfi.NegativeSign, 0, nfi.NegativeSign.Length) == 0) {
+                               negative = true;
+                               foundSign = true;
+                               pos += nfi.NegativeSign.Length;
+                       } else if ((pos + nfi.PositiveSign.Length) <= s.Length &&
+                           string.CompareOrdinal(s, pos, nfi.PositiveSign, 0, nfi.PositiveSign.Length) == 0) {
+                               negative = false;
+                               pos += nfi.PositiveSign.Length;
+                               foundSign = true;
+                       } 
+               }
+
+               internal static void FindCurrency (ref int pos,
+                                                string s, 
+                                                NumberFormatInfo nfi,
+                                                ref bool foundCurrency)
+               {
+                       if ((pos + nfi.CurrencySymbol.Length) <= s.Length &&
+                            s.Substring (pos, nfi.CurrencySymbol.Length) == nfi.CurrencySymbol) {
+                               foundCurrency = true;
+                               pos += nfi.CurrencySymbol.Length;
+                       } 
+               }
+
+               internal static bool FindExponent (ref int pos, string s, ref int exponent, bool tryParse, ref Exception exc)
+               {
+                       exponent = 0;
+
+                       if (pos >= s.Length || (s [pos] != 'e' && s[pos] != 'E')) {
+                               exc = null;
+                               return false;
+                       }
+
+                       var i = pos + 1;
+                       if (i == s.Length) {
+                               exc = tryParse ? null : GetFormatException ();
+                               return true;
+                       }
+
+                       bool negative = false;
+                       if (s [i] == '-') {
+                               negative = true;
+                               if(++i == s.Length){
+                                       exc = tryParse ? null : GetFormatException ();
+                                       return true;
+                               }
+                       }
+
+                       if (s [i] == '+' && ++i == s.Length) {
+                               exc = tryParse ? null : GetFormatException ();
+                               return true;
+                       }
+
+                       long exp = 0; // temp long value
+                       for (; i < s.Length; i++) {
+                               if (!Char.IsDigit (s [i]))  {
+                                       exc = tryParse ? null : GetFormatException ();
+                                       return true;
+                               }
+
+                               // Reduce the risk of throwing an overflow exc
+                               exp = checked (exp * 10 - (int) (s [i] - '0'));
+                               if (exp < Int32.MinValue || exp > Int32.MaxValue) {
+                                       exc = tryParse ? null : new OverflowException ("Value too large or too small.");
+                                       return true;
+                               }
+                       }
+
+                       // exp value saved as negative
+                       if(!negative)
+                               exp = -exp;
+
+                       exc = null;
+                       exponent = (int)exp;
+                       pos = i;
+                       return true;
+               }
+
+               internal static bool FindOther (ref int pos, string s, string other)
+               {
+                       if ((pos + other.Length) <= s.Length &&
+                            s.Substring (pos, other.Length) == other) {
+                               pos += other.Length;
+                               return true;
+                       } 
+
+                       return false;
+               }
+
+               internal static bool ValidDigit (char e, bool allowHex)
+               {
+                       if (allowHex)
+                               return Char.IsDigit (e) || (e >= 'A' && e <= 'F') || (e >= 'a' && e <= 'f');
+
+                       return Char.IsDigit (e);
+               }
+
+               static Exception GetFormatException ()
+               {
+                       return new FormatException ("Input string was not in the correct format");
+               }
+
+               static bool ProcessTrailingWhitespace (bool tryParse, string s, int position, ref Exception exc)
+               {
+                       int len = s.Length;
+                       
+                       for (int i = position; i < len; i++){
+                               char c = s [i];
+                               
+                               if (c != 0 && !Char.IsWhiteSpace (c)){
+                                       if (!tryParse)
+                                               exc = GetFormatException ();
+                                       return false;
+                               }
+                       }
+                       return true;
+               }
+
+               static bool Parse (string s, bool tryParse, out BigInteger result, out Exception exc)
+               {
+                       int len;
+                       int i, sign = 1;
+                       bool digits_seen = false;
+
+                       result = Zero;
+                       exc = null;
+
+                       if (s == null) {
+                               if (!tryParse)
+                                       exc = new ArgumentNullException ("value");
+                               return false;
+                       }
+
+                       len = s.Length;
+
+                       char c;
+                       for (i = 0; i < len; i++){
+                               c = s [i];
+                               if (!Char.IsWhiteSpace (c))
+                                       break;
+                       }
+                       
+                       if (i == len) {
+                               if (!tryParse)
+                                       exc = GetFormatException ();
+                               return false;
+                       }
+
+                       var info = Thread.CurrentThread.CurrentCulture.NumberFormat;
+                       
+                       string negative = info.NegativeSign;
+                       string positive = info.PositiveSign;
+
+                       if (string.CompareOrdinal (s, i, positive, 0, positive.Length) == 0)
+                               i += positive.Length;
+                       else if (string.CompareOrdinal (s, i, negative, 0, negative.Length) == 0) {
+                               sign = -1;
+                               i += negative.Length;
+                       }
+
+                       BigInteger val = Zero;
+                       for (; i < len; i++){
+                               c = s [i];
+
+                               if (c == '\0') {
+                                       i = len;
+                                       continue;
+                               }
+
+                               if (c >= '0' && c <= '9'){
+                                       byte d = (byte) (c - '0');
+
+                                       val = val * 10 + d;
+
+                                       digits_seen = true;
+                               } else if (!ProcessTrailingWhitespace (tryParse, s, i, ref exc))
+                                       return false;
+                       }
+
+                       if (!digits_seen) {
+                               if (!tryParse)
+                                       exc = GetFormatException ();
+                               return false;
+                       }
+
+                       if (val.sign == 0)
+                               result = val;
+                       else if (sign == -1)
+                               result = new BigInteger (-1, val.data);
+                       else
+                               result = new BigInteger (1, val.data);
+
+                       return true;
+               }
+
+               public static BigInteger Min (BigInteger left, BigInteger right)
+               {
+                       int ls = left.sign;
+                       int rs = right.sign;
+
+                       if (ls < rs)
+                               return left;
+                       if (rs < ls)
+                               return right;
+
+                       int r = CoreCompare (left.data, right.data);
+                       if (ls == -1)
+                               r = -r;
+
+                       if (r <= 0)
+                               return left;
+                       return right;
+               }
+
+
+               public static BigInteger Max (BigInteger left, BigInteger right)
+               {
+                       int ls = left.sign;
+                       int rs = right.sign;
+
+                       if (ls > rs)
+                               return left;
+                       if (rs > ls)
+                               return right;
+
+                       int r = CoreCompare (left.data, right.data);
+                       if (ls == -1)
+                               r = -r;
+
+                       if (r >= 0)
+                               return left;
+                       return right;
+               }
+
+               public static BigInteger Abs (BigInteger value)
+               {
+                       return new BigInteger ((short)Math.Abs (value.sign), value.data);
+               }
+
+
+               public static BigInteger DivRem (BigInteger dividend, BigInteger divisor, out BigInteger remainder)
+               {
+                       if (divisor.sign == 0)
+                               throw new DivideByZeroException ();
+
+                       if (dividend.sign == 0) {
+                               remainder = dividend;
+                               return dividend;
+                       }
+
+                       uint[] quotient;
+                       uint[] remainder_value;
+
+                       DivModUnsigned (dividend.data, divisor.data, out quotient, out remainder_value);
+
+                       int i;
+                       for (i = remainder_value.Length - 1; i >= 0 && remainder_value [i] == 0; --i) ;
+                       if (i == -1) {
+                               remainder = new BigInteger (0, ZERO);
+                       } else {
+                               if (i < remainder_value.Length - 1)
+                                       remainder_value = Resize (remainder_value, i + 1);
+                               remainder = new BigInteger (dividend.sign, remainder_value);
+                       }
+
+                       for (i = quotient.Length - 1; i >= 0 && quotient [i] == 0; --i) ;
+                       if (i == -1)
+                               return new BigInteger (0, ZERO);
+                       if (i < quotient.Length - 1)
+                               quotient = Resize (quotient, i + 1);
+
+                       return new BigInteger ((short)(dividend.sign * divisor.sign), quotient);
+               }
+
+        public static BigInteger Pow (BigInteger value, int exponent)
+               {
+                       if (exponent < 0)
+                               throw new ArgumentOutOfRangeException("exponent", "exp must be >= 0");
+                       if (exponent == 0)
+                               return One;
+                       if (exponent == 1)
+                               return value;
+
+                       BigInteger result = One;
+                       while (exponent != 0) {
+                               if ((exponent & 1) != 0)
+                                       result = result * value;
+                               if (exponent == 1)
+                                       break;
+
+                               value = value * value;
+                               exponent >>= 1;
+                       }
+                       return result;
+        }
+
+               public static BigInteger ModPow (BigInteger value, BigInteger exponent, BigInteger modulus) {
+                       if (exponent.sign == -1)
+                               throw new ArgumentOutOfRangeException("exponent", "power must be >= 0");
+                       if (modulus.sign == 0)
+                               throw new DivideByZeroException ();
+
+                       BigInteger result = One % modulus;
+                       while (exponent.sign != 0) {
+                               if (!exponent.IsEven) {
+                                       result = result * value;
+                                       result = result % modulus;
+                               }
+                               if (exponent.IsOne)
+                                       break;
+                               value = value * value;
+                               value = value % modulus;
+                               exponent >>= 1;
+                       }
+                       return result;
+               }
+
+               public static BigInteger GreatestCommonDivisor (BigInteger left, BigInteger right)
+               {
+                       if (left.sign != 0 && left.data.Length == 1 && left.data [0] == 1)
+                               return new BigInteger (1, ONE);
+                       if (right.sign != 0 && right.data.Length == 1 && right.data [0] == 1)
+                               return new BigInteger (1, ONE);
+                       if (left.IsZero)
+                               return Abs(right);
+                       if (right.IsZero)
+                               return Abs(left);
+
+                       BigInteger x = new BigInteger (1, left.data);
+                       BigInteger y = new BigInteger (1, right.data);
+
+                       BigInteger g = y;
+
+                       while (x.data.Length > 1) {
+                               g = x;
+                               x = y % x;
+                               y = g;
+
+                       }
+                       if (x.IsZero) return g;
+
+                       // TODO: should we have something here if we can convert to long?
+
+                       //
+                       // Now we can just do it with single precision. I am using the binary gcd method,
+                       // as it should be faster.
+                       //
+
+                       uint yy = x.data [0];
+                       uint xx = (uint)(y % yy);
+
+                       int t = 0;
+
+                       while (((xx | yy) & 1) == 0) {
+                               xx >>= 1; yy >>= 1; t++;
+                       }
+                       while (xx != 0) {
+                               while ((xx & 1) == 0) xx >>= 1;
+                               while ((yy & 1) == 0) yy >>= 1;
+                               if (xx >= yy)
+                                       xx = (xx - yy) >> 1;
+                               else
+                                       yy = (yy - xx) >> 1;
+                       }
+
+                       return yy << t;
+               }
+
+               /*LAMESPEC Log doesn't specify to how many ulp is has to be precise
+               We are equilavent to MS with about 2 ULP
+               */
+               public static double Log (BigInteger value, Double baseValue)
+               {
+                       if (value.sign == -1 || baseValue == 1.0d || baseValue == -1.0d ||
+                                       baseValue == Double.NegativeInfinity || double.IsNaN (baseValue))
+                               return double.NaN;
+
+                       if (baseValue == 0.0d || baseValue == Double.PositiveInfinity)
+                               return value.IsOne ? 0 : double.NaN;
+       
+                       if (value.sign == 0)
+                               return double.NegativeInfinity;
+
+                       int length = value.data.Length - 1;
+                       int bitCount = -1;
+                       for (int curBit = 31; curBit >= 0; curBit--) {
+                               if ((value.data [length] & (1 << curBit)) != 0) {
+                                       bitCount = curBit + length * 32;
+                                       break;
+                               }
+                       }
+
+                       long bitlen = bitCount;
+                       Double c = 0, d = 1;
+
+                       BigInteger testBit = One;
+                       long tempBitlen = bitlen;
+                       while (tempBitlen > Int32.MaxValue) {
+                               testBit = testBit << Int32.MaxValue;
+                               tempBitlen -= Int32.MaxValue;
+                       }
+                       testBit = testBit << (int)tempBitlen;
+
+                       for (long curbit = bitlen; curbit >= 0; --curbit) {
+                               if ((value & testBit).sign != 0)
+                                       c += d;
+                               d *= 0.5;
+                               testBit = testBit >> 1;
+                       }
+                       return (System.Math.Log (c) + System.Math.Log (2) * bitlen) / System.Math.Log (baseValue);
+               }
+
+
+        public static double Log (BigInteger value)
+               {
+            return Log (value, Math.E);
+        }
+
+
+        public static double Log10 (BigInteger value)
+               {
+            return Log (value, 10);
+        }
+
+               [CLSCompliantAttribute (false)]
+               public bool Equals (ulong other)
+               {
+                       return CompareTo (other) == 0;
+               }
+
+               public override int GetHashCode ()
+               {
+                       uint hash = (uint)(sign * 0x01010101u);
+                       int len = data != null ? data.Length : 0;
+
+                       for (int i = 0; i < len; ++i)
+                               hash ^= data [i];
+                       return (int)hash;
+               }
+
+               public static BigInteger Add (BigInteger left, BigInteger right)
+               {
+                       return left + right;
+               }
+
+               public static BigInteger Subtract (BigInteger left, BigInteger right)
+               {
+                       return left - right;
+               }
+
+               public static BigInteger Multiply (BigInteger left, BigInteger right)
+               {
+                       return left * right;
+               }
+
+               public static BigInteger Divide (BigInteger dividend, BigInteger divisor)
+               {
+                       return dividend / divisor;
+               }
+
+               public static BigInteger Remainder (BigInteger dividend, BigInteger divisor)
+               {
+                       return dividend % divisor;
+               }
+
+               public static BigInteger Negate (BigInteger value)
+               {
+                       return - value;
+               }
+
+               public int CompareTo (object obj)
+               {
+                       if (obj == null)
+                               return 1;
+                       
+                       if (!(obj is BigInteger))
+                               return -1;
+
+                       return Compare (this, (BigInteger)obj);
+               }
+
+               public int CompareTo (BigInteger other)
+               {
+                       return Compare (this, other);
+               }
+
+               [CLSCompliantAttribute (false)]
+               public int CompareTo (ulong other)
+               {
+                       if (sign < 0)
+                               return -1;
+                       if (sign == 0)
+                               return other == 0 ? 0 : -1;
+
+                       if (data.Length > 2)
+                               return 1;
+
+                       uint high = (uint)(other >> 32);
+                       uint low = (uint)other;
+
+                       return LongCompare (low, high);
+               }
+
+               int LongCompare (uint low, uint high)
+               {
+                       uint h = 0;
+                       if (data.Length > 1)
+                               h = data [1];
+
+                       if (h > high)
+                               return 1;
+                       if (h < high)
+                               return -1;
+
+                       uint l = data [0];
+
+                       if (l > low)
+                               return 1;
+                       if (l < low)
+                               return -1;
+
+                       return 0;
+               }
+
+               public int CompareTo (long other)
+               {
+                       int ls = sign;
+                       int rs = Math.Sign (other);
+
+                       if (ls != rs)
+                               return ls > rs ? 1 : -1;
+
+                       if (ls == 0)
+                               return 0;
+
+                       if (data.Length > 2)
+                               return sign;
+
+                       if (other < 0)
+                               other = -other;
+                       uint low = (uint)other;
+                       uint high = (uint)((ulong)other >> 32);
+
+                       int r = LongCompare (low, high);
+                       if (ls == -1)
+                               r = -r;
+
+                       return r;
+               }
+
+               public static int Compare (BigInteger left, BigInteger right)
+               {
+                       int ls = left.sign;
+                       int rs = right.sign;
+
+                       if (ls != rs)
+                               return ls > rs ? 1 : -1;
+
+                       int r = CoreCompare (left.data, right.data);
+                       if (ls < 0)
+                               r = -r;
+                       return r;
+               }
+
+
+               static int TopByte (uint x)
+               {
+                       if ((x & 0xFFFF0000u) != 0) {
+                               if ((x & 0xFF000000u) != 0)
+                                       return 4;
+                               return 3;
+                       }
+                       if ((x & 0xFF00u) != 0)
+                               return 2;
+                       return 1;       
+               }
+
+               static int FirstNonFFByte (uint word)
+               {
+                       if ((word & 0xFF000000u) != 0xFF000000u)
+                               return 4;
+                       else if ((word & 0xFF0000u) != 0xFF0000u)
+                               return 3;
+                       else if ((word & 0xFF00u) != 0xFF00u)
+                               return 2;
+                       return 1;
+               }
+
+               public byte[] ToByteArray ()
+               {
+                       if (sign == 0)
+                               return new byte [1];
+
+                       //number of bytes not counting upper word
+                       int bytes = (data.Length - 1) * 4;
+                       bool needExtraZero = false;
+
+                       uint topWord = data [data.Length - 1];
+                       int extra;
+
+                       //if the topmost bit is set we need an extra 
+                       if (sign == 1) {
+                               extra = TopByte (topWord);
+                               uint mask = 0x80u << ((extra - 1) * 8);
+                               if ((topWord & mask) != 0) {
+                                       needExtraZero = true;
+                               }
+                       } else {
+                               extra = TopByte (topWord);
+                       }
+
+                       byte[] res = new byte [bytes + extra + (needExtraZero ? 1 : 0) ];
+                       if (sign == 1) {
+                               int j = 0;
+                               int end = data.Length - 1;
+                               for (int i = 0; i < end; ++i) {
+                                       uint word = data [i];
+
+                                       res [j++] = (byte)word;
+                                       res [j++] = (byte)(word >> 8);
+                                       res [j++] = (byte)(word >> 16);
+                                       res [j++] = (byte)(word >> 24);
+                               }
+                               while (extra-- > 0) {
+                                       res [j++] = (byte)topWord;
+                                       topWord >>= 8;
+                               }
+                       } else {
+                               int j = 0;
+                               int end = data.Length - 1;
+
+                               uint carry = 1, word;
+                               ulong add;
+                               for (int i = 0; i < end; ++i) {
+                                       word = data [i];
+                                       add = (ulong)~word + carry;
+                                       word = (uint)add;
+                                       carry = (uint)(add >> 32);
+
+                                       res [j++] = (byte)word;
+                                       res [j++] = (byte)(word >> 8);
+                                       res [j++] = (byte)(word >> 16);
+                                       res [j++] = (byte)(word >> 24);
+                               }
+
+                               add = (ulong)~topWord + (carry);
+                               word = (uint)add;
+                               carry = (uint)(add >> 32);
+                               if (carry == 0) {
+                                       int ex = FirstNonFFByte (word);
+                                       bool needExtra = (word & (1 << (ex * 8 - 1))) == 0;
+                                       int to = ex + (needExtra ? 1 : 0);
+
+                                       if (to != extra)
+                                               res = Resize (res, bytes + to);
+
+                                       while (ex-- > 0) {
+                                               res [j++] = (byte)word;
+                                               word >>= 8;
+                                       }
+                                       if (needExtra)
+                                               res [j++] = 0xFF;
+                               } else {
+                                       res = Resize (res, bytes + 5);
+                                       res [j++] = (byte)word;
+                                       res [j++] = (byte)(word >> 8);
+                                       res [j++] = (byte)(word >> 16);
+                                       res [j++] = (byte)(word >> 24);
+                                       res [j++] = 0xFF;
+                               }
+                       }
+
+                       return res;
+               }
+
+               static byte[] Resize (byte[] v, int len)
+               {
+                       byte[] res = new byte [len];
+                       Array.Copy (v, res, Math.Min (v.Length, len));
+                       return res;
+               }
+
+               static uint[] Resize (uint[] v, int len)
+               {
+                       uint[] res = new uint [len];
+                       Array.Copy (v, res, Math.Min (v.Length, len));
+                       return res;
+               }
+
+               static uint[] CoreAdd (uint[] a, uint[] b)
+               {
+                       if (a.Length < b.Length) {
+                               uint[] tmp = a;
+                               a = b;
+                               b = tmp;
+                       }
+
+                       int bl = a.Length;
+                       int sl = b.Length;
+
+                       uint[] res = new uint [bl];
+
+                       ulong sum = 0;
+
+                       int i = 0;
+                       for (; i < sl; i++) {
+                               sum = sum + a [i] + b [i];
+                               res [i] = (uint)sum;
+                               sum >>= 32;
+                       }
+
+                       for (; i < bl; i++) {
+                               sum = sum + a [i];
+                               res [i] = (uint)sum;
+                               sum >>= 32;
+                       }
+
+                       if (sum != 0) {
+                               res = Resize (res, bl + 1);
+                               res [i] = (uint)sum;
+                       }
+
+                       return res;
+               }
+
+               /*invariant a > b*/
+               static uint[] CoreSub (uint[] a, uint[] b)
+               {
+                       int bl = a.Length;
+                       int sl = b.Length;
+
+                       uint[] res = new uint [bl];
+
+                       ulong borrow = 0;
+                       int i;
+                       for (i = 0; i < sl; ++i) {
+                               borrow = (ulong)a [i] - b [i] - borrow;
+
+                               res [i] = (uint)borrow;
+                               borrow = (borrow >> 32) & 0x1;
+                       }
+
+                       for (; i < bl; i++) {
+                               borrow = (ulong)a [i] - borrow;
+                               res [i] = (uint)borrow;
+                               borrow = (borrow >> 32) & 0x1;
+                       }
+
+                       //remove extra zeroes
+                       for (i = bl - 1; i >= 0 && res [i] == 0; --i) ;
+                       if (i < bl - 1)
+                               res = Resize (res, i + 1);
+
+            return res;
+               }
+
+
+               static uint[] CoreAdd (uint[] a, uint b)
+               {
+                       int len = a.Length;
+                       uint[] res = new uint [len];
+
+                       ulong sum = b;
+                       int i;
+                       for (i = 0; i < len; i++) {
+                               sum = sum + a [i];
+                               res [i] = (uint)sum;
+                               sum >>= 32;
+                       }
+
+                       if (sum != 0) {
+                               res = Resize (res, len + 1);
+                               res [i] = (uint)sum;
+                       }
+
+                       return res;
+               }
+
+               static uint[] CoreSub (uint[] a, uint b)
+               {
+                       int len = a.Length;
+                       uint[] res = new uint [len];
+
+                       ulong borrow = b;
+                       int i;
+                       for (i = 0; i < len; i++) {
+                               borrow = (ulong)a [i] - borrow;
+                               res [i] = (uint)borrow;
+                               borrow = (borrow >> 32) & 0x1;
+                       }
+
+                       //remove extra zeroes
+                       for (i = len - 1; i >= 0 && res [i] == 0; --i) ;
+                       if (i < len - 1)
+                               res = Resize (res, i + 1);
+
+            return res;
+               }
+
+               static int CoreCompare (uint[] a, uint[] b)
+               {
+                       int al = a != null ? a.Length : 0;
+                       int bl = b != null ? b.Length : 0;
+
+                       if (al > bl)
+                               return 1;
+                       if (bl > al)
+                               return -1;
+
+                       for (int i = al - 1; i >= 0; --i) {
+                               uint ai = a [i];
+                               uint bi = b [i];
+                               if (ai > bi)    
+                                       return 1;
+                               if (ai < bi)    
+                                       return -1;
+                       }
+                       return 0;
+               }
+
+               static int GetNormalizeShift(uint value) {
+                       int shift = 0;
+
+                       if ((value & 0xFFFF0000) == 0) { value <<= 16; shift += 16; }
+                       if ((value & 0xFF000000) == 0) { value <<= 8; shift += 8; }
+                       if ((value & 0xF0000000) == 0) { value <<= 4; shift += 4; }
+                       if ((value & 0xC0000000) == 0) { value <<= 2; shift += 2; }
+                       if ((value & 0x80000000) == 0) { value <<= 1; shift += 1; }
+
+                       return shift;
+               }
+
+               static void Normalize (uint[] u, int l, uint[] un, int shift)
+               {
+                       uint carry = 0;
+                       int i;
+                       if (shift > 0) {
+                               int rshift = 32 - shift;
+                               for (i = 0; i < l; i++) {
+                                       uint ui = u [i];
+                                       un [i] = (ui << shift) | carry;
+                                       carry = ui >> rshift;
+                               }
+                       } else {
+                               for (i = 0; i < l; i++) {
+                                       un [i] = u [i];
+                               }
+                       }
+
+                       while (i < un.Length) {
+                               un [i++] = 0;
+                       }
+
+                       if (carry != 0) {
+                               un [l] = carry;
+                       }
+               }
+
+               static void Unnormalize (uint[] un, out uint[] r, int shift)
+               {
+                       int length = un.Length;
+                       r = new uint [length];
+
+                       if (shift > 0) {
+                               int lshift = 32 - shift;
+                               uint carry = 0;
+                               for (int i = length - 1; i >= 0; i--) {
+                                       uint uni = un [i];
+                                       r [i] = (uni >> shift) | carry;
+                                       carry = (uni << lshift);
+                               }
+                       } else {
+                               for (int i = 0; i < length; i++) {
+                                       r [i] = un [i];
+                               }
+                       }
+               }
+
+               const ulong Base = 0x100000000;
+               static void DivModUnsigned (uint[] u, uint[] v, out uint[] q, out uint[] r)
+               {
+                       int m = u.Length;
+                       int n = v.Length;
+
+                       if (n <= 1) {
+                               //  Divide by single digit
+                               //
+                               ulong rem = 0;
+                               uint v0 = v [0];
+                               q = new uint[m];
+                               r = new uint [1];
+
+                               for (int j = m - 1; j >= 0; j--) {
+                                       rem *= Base;
+                                       rem += u[j];
+
+                                       ulong div = rem / v0;
+                                       rem -= div * v0;
+                                       q[j] = (uint)div;
+                               }
+                               r [0] = (uint)rem;
+                       } else if (m >= n) {
+                               int shift = GetNormalizeShift (v [n - 1]);
+
+                               uint[] un = new uint [m + 1];
+                               uint[] vn = new uint [n];
+
+                               Normalize (u, m, un, shift);
+                               Normalize (v, n, vn, shift);
+
+                               q = new uint [m - n + 1];
+                               r = null;
+
+                               //  Main division loop
+                               //
+                               for (int j = m - n; j >= 0; j--) {
+                                       ulong rr, qq;
+                                       int i;
+
+                                       rr = Base * un [j + n] + un [j + n - 1];
+                                       qq = rr / vn [n - 1];
+                                       rr -= qq * vn [n - 1];
+
+                                       for (; ; ) {
+                                               // Estimate too big ?
+                                               //
+                                               if ((qq >= Base) || (qq * vn [n - 2] > (rr * Base + un [j + n - 2]))) {
+                                                       qq--;
+                                                       rr += (ulong)vn [n - 1];
+                                                       if (rr < Base)
+                                                               continue;
+                                               }
+                                               break;
+                                       }
+
+
+                                       //  Multiply and subtract
+                                       //
+                                       long b = 0;
+                                       long t = 0;
+                                       for (i = 0; i < n; i++) {
+                                               ulong p = vn [i] * qq;
+                                               t = (long)un [i + j] - (long)(uint)p - b;
+                                               un [i + j] = (uint)t;
+                                               p >>= 32;
+                                               t >>= 32;
+                                               b = (long)p - t;
+                                       }
+                                       t = (long)un [j + n] - b;
+                                       un [j + n] = (uint)t;
+
+                                       //  Store the calculated value
+                                       //
+                                       q [j] = (uint)qq;
+
+                                       //  Add back vn[0..n] to un[j..j+n]
+                                       //
+                                       if (t < 0) {
+                                               q [j]--;
+                                               ulong c = 0;
+                                               for (i = 0; i < n; i++) {
+                                                       c = (ulong)vn [i] + un [j + i] + c;
+                                                       un [j + i] = (uint)c;
+                                                       c >>= 32;
+                                               }
+                                               c += (ulong)un [j + n];
+                                               un [j + n] = (uint)c;
+                                       }
+                               }
+
+                               Unnormalize (un, out r, shift);
+                       } else {
+                               q = new uint [] { 0 };
+                               r = u;
+                       }
+               }
+       }
+}