Пример #1
0
        public static EInteger FromRadixSubstringImpl(
            char[] cs,
            int radix,
            int index,
            int endIndex,
            bool throwException)
        {
            if (radix < 2)
            {
                if (!throwException)
                {
                    return(null);
                }
                else
                {
                    throw new ArgumentException("radix(" + radix + ") is less than 2");
                }
            }
            if (radix > 36)
            {
                if (!throwException)
                {
                    return(null);
                }
                else
                {
                    throw new ArgumentException("radix(" + radix + ") is more than 36");
                }
            }
            if (index < 0)
            {
                if (!throwException)
                {
                    return(null);
                }
                else
                {
                    throw new ArgumentException("index(" + index + ") is less than " + "0");
                }
            }
            if (index > cs.Length)
            {
                if (!throwException)
                {
                    return(null);
                }
                else
                {
                    throw new ArgumentException("index(" + index + ") is more than " + cs.Length);
                }
            }
            if (endIndex < 0)
            {
                if (!throwException)
                {
                    return(null);
                }
                else
                {
                    throw new ArgumentException("endIndex(" + endIndex + ") is less than 0");
                }
            }
            if (endIndex > cs.Length)
            {
                if (!throwException)
                {
                    return(null);
                }
                else
                {
                    throw new ArgumentException("endIndex(" + endIndex + ") is more than " +
                                                cs.Length);
                }
            }
            if (endIndex < index)
            {
                if (!throwException)
                {
                    return(null);
                }
                else
                {
                    throw new ArgumentException("endIndex(" + endIndex + ") is less than " +
                                                index);
                }
            }
            if (index == endIndex)
            {
                if (!throwException)
                {
                    return(null);
                }
                else
                {
                    throw new FormatException("No digits");
                }
            }
            var negative = false;

            if (cs[index] == '-')
            {
                ++index;
                if (index == endIndex)
                {
                    if (!throwException)
                    {
                        return(null);
                    }
                    else
                    {
                        throw new FormatException("No digits");
                    }
                }
                negative = true;
            }
            // Skip leading zeros
            for (; index < endIndex; ++index)
            {
                char c = cs[index];
                if (c != 0x30)
                {
                    break;
                }
            }
            int effectiveLength = endIndex - index;

            if (effectiveLength == 0)
            {
                return(EInteger.Zero);
            }
            int[]   c2d = EInteger.CharToDigit;
            short[] bigint;
            if (radix == 16)
            {
                // Special case for hexadecimal radix
                int leftover  = effectiveLength & 3;
                int wordCount = effectiveLength >> 2;
                if (leftover != 0)
                {
                    ++wordCount;
                }
                bigint = new short[wordCount];
                int currentDigit = wordCount - 1;
                // Get most significant digits if effective
                // length is not divisible by 4
                if (leftover != 0)
                {
                    var extraWord = 0;
                    for (int i = 0; i < leftover; ++i)
                    {
                        extraWord <<= 4;
                        char c     = cs[index + i];
                        int  digit = (c >= 0x80) ? 36 : c2d[(int)c];
                        if (digit >= 16)
                        {
                            if (!throwException)
                            {
                                return(null);
                            }
                            else
                            {
                                throw new FormatException("Illegal character found");
                            }
                        }
                        extraWord |= digit;
                    }
                    bigint[currentDigit] = unchecked ((short)extraWord);
                    --currentDigit;
                    index += leftover;
                }
        #if DEBUG
                if ((endIndex - index) % 4 != 0)
                {
                    if (!throwException)
                    {
                        return(null);
                    }
                    else
                    {
                        throw new InvalidOperationException("doesn't satisfy (endIndex - index) %" +
                                                            "\u00204 == 0");
                    }
                }
        #endif
                while (index < endIndex)
                {
                    char c     = cs[index + 3];
                    int  digit = (c >= 0x80) ? 36 : c2d[(int)c];
                    if (digit >= 16)
                    {
                        if (!throwException)
                        {
                            return(null);
                        }
                        else
                        {
                            throw new FormatException("Illegal character found");
                        }
                    }
                    int word = digit;
                    c     = cs[index + 2];
                    digit = (c >= 0x80) ? 36 : c2d[(int)c];
                    if (digit >= 16)
                    {
                        if (!throwException)
                        {
                            return(null);
                        }
                        else
                        {
                            throw new FormatException("Illegal character found");
                        }
                    }

                    word |= digit << 4;
                    c     = cs[index + 1];
                    digit = (c >= 0x80) ? 36 : c2d[(int)c];
                    if (digit >= 16)
                    {
                        if (!throwException)
                        {
                            return(null);
                        }
                        else
                        {
                            throw new FormatException("Illegal character found");
                        }
                    }

                    word |= digit << 8;
                    c     = cs[index];
                    digit = (c >= 0x80) ? 36 : c2d[(int)c];
                    if (digit >= 16)
                    {
                        if (!throwException)
                        {
                            return(null);
                        }
                        else
                        {
                            throw new FormatException("Illegal character found");
                        }
                    }
                    word  |= digit << 12;
                    index += 4;
                    bigint[currentDigit] = unchecked ((short)word);
                    --currentDigit;
                }
                int count = EInteger.CountWords(bigint);
                return((count == 0) ? EInteger.Zero : new EInteger(
                           count,
                           bigint,
                           negative));
            }
            else if (radix == 2)
            {
                // Special case for binary radix
                int leftover  = effectiveLength & 15;
                int wordCount = effectiveLength >> 4;
                if (leftover != 0)
                {
                    ++wordCount;
                }
                bigint = new short[wordCount];
                int currentDigit = wordCount - 1;
                // Get most significant digits if effective
                // length is not divisible by 4
                if (leftover != 0)
                {
                    var extraWord = 0;
                    for (int i = 0; i < leftover; ++i)
                    {
                        extraWord <<= 1;
                        char c     = cs[index + i];
                        int  digit = (c == '0') ? 0 : ((c == '1') ? 1 : 2);
                        if (digit >= 2)
                        {
                            if (!throwException)
                            {
                                return(null);
                            }
                            else
                            {
                                throw new FormatException("Illegal character found");
                            }
                        }
                        extraWord |= digit;
                    }
                    bigint[currentDigit] = unchecked ((short)extraWord);
                    --currentDigit;
                    index += leftover;
                }
                while (index < endIndex)
                {
                    var word = 0;
                    int idx  = index + 15;
                    for (var i = 0; i < 16; ++i)
                    {
                        char c     = cs[idx];
                        int  digit = (c == '0') ? 0 : ((c == '1') ? 1 : 2);
                        if (digit >= 2)
                        {
                            if (!throwException)
                            {
                                return(null);
                            }
                            else
                            {
                                throw new FormatException("Illegal character found");
                            }
                        }
                        --idx;
                        word |= digit << i;
                    }
                    index += 16;
                    bigint[currentDigit] = unchecked ((short)word);
                    --currentDigit;
                }
                int count = EInteger.CountWords(bigint);
                return((count == 0) ? EInteger.Zero : new EInteger(
                           count,
                           bigint,
                           negative));
            }
            else
            {
                return(FromRadixSubstringGeneral(
                           cs,
                           radix,
                           index,
                           endIndex,
                           negative,
                           throwException));
            }
        }
Пример #2
0
        private static EInteger FromRadixSubstringInner(
            char[] cs,
            int radix,
            int index,
            int endIndex,
            bool negative,
            bool throwException)
        {
            if (radix <= 10)
            {
                long rv         = 0;
                var  digitCount = 0;
                if (radix == 10)
                {
                    for (int i = index; i < endIndex; ++i)
                    {
                        char c     = cs[i];
                        var  digit = (int)c - 0x30;
                        if (digit >= radix || digit < 0)
                        {
                            if (!throwException)
                            {
                                return(null);
                            }
                            else
                            {
                                throw new FormatException("Illegal character found");
                            }
                        }
                        if (digitCount < 0 || digitCount >= 18)
                        {
                            digitCount = -1;
                            break;
                        }
                        else if (digitCount > 0 || digit != 0)
                        {
                            ++digitCount;
                        }
                        rv = (rv * 10) + digit;
                    }
                    // DebugUtility.Log("short="+(negative ? -rv : rv));
                    if (digitCount >= 0)
                    {
                        return(EInteger.FromInt64(negative ? -rv : rv));
                    }
                }
                else
                {
                    for (int i = index; i < endIndex; ++i)
                    {
                        char c     = cs[i];
                        int  digit = (c >= 0x80) ? 36 : ((int)c - 0x30);
                        if (digit >= radix || digit < 0)
                        {
                            if (!throwException)
                            {
                                return(null);
                            }
                            else
                            {
                                throw new FormatException("Illegal character found");
                            }
                        }
                        if (digitCount < 0 || digitCount >= 18)
                        {
                            digitCount = -1;
                            break;
                        }
                        else if (digitCount > 0 || digit != 0)
                        {
                            ++digitCount;
                        }
                        rv = (rv * radix) + digit;
                    }
                    if (digitCount >= 0)
                    {
                        return(EInteger.FromInt64(negative ? -rv : rv));
                    }
                }
            }
            int[] c2d   = EInteger.CharToDigit;
            int[] d2w   = EInteger.DigitsInWord;
            long  lsize = ((long)(endIndex - index) * 100 / d2w[radix]) + 1;

            lsize = Math.Min(lsize, Int32.MaxValue);
            lsize = Math.Max(lsize, 5);
            var bigint = new short[(int)lsize];

            if (radix == 10)
            {
                long rv = 0;
                int  ei = endIndex - index <= 18 ? endIndex : index + 18;
                for (int i = index; i < ei; ++i)
                {
                    char c     = cs[i];
                    var  digit = (int)c - 0x30;
                    if (digit >= radix || digit < 0)
                    {
                        if (!throwException)
                        {
                            return(null);
                        }
                        else
                        {
                            throw new FormatException("Illegal character found");
                        }
                    }
                    rv = (rv * 10) + digit;
                }
                bigint[0] = unchecked ((short)(rv & ShortMask));
                bigint[1] = unchecked ((short)((rv >> 16) & ShortMask));
                bigint[2] = unchecked ((short)((rv >> 32) & ShortMask));
                bigint[3] = unchecked ((short)((rv >> 48) & ShortMask));
                int bn = Math.Min(bigint.Length, 5);
                for (int i = ei; i < endIndex; ++i)
                {
                    short carry = 0;
                    var   digit = 0;
                    var   overf = 0;
                    if (i < endIndex - 3)
                    {
                        overf = 55536; // 2**16 minus 10**4
                        var d1 = (int)cs[i] - 0x30;
                        var d2 = (int)cs[i + 1] - 0x30;
                        var d3 = (int)cs[i + 2] - 0x30;
                        var d4 = (int)cs[i + 3] - 0x30;
                        i += 3;
                        if (d1 >= 10 || d1 < 0 || d2 >= 10 || d2 < 0 || d3 >= 10 ||
                            d3 < 0 || d4 >= 10 || d4 < 0)
                        {
                            if (!throwException)
                            {
                                return(null);
                            }
                            else
                            {
                                throw new FormatException("Illegal character found");
                            }
                        }
                        digit = (d1 * 1000) + (d2 * 100) + (d3 * 10) + d4;
                        // Multiply by 10**4
                        for (int j = 0; j < bn; ++j)
                        {
                            int p;
                            p = unchecked ((((int)bigint[j]) & ShortMask) *
                                           10000);
                            int p2 = ((int)carry) & ShortMask;
                            p         = unchecked (p + p2);
                            bigint[j] = unchecked ((short)p);
                            carry     = unchecked ((short)(p >> 16));
                        }
                    }
                    else
                    {
                        overf = 65526; // 2**16 minus radix 10
                        char c = cs[i];
                        digit = (int)c - 0x30;
                        if (digit >= 10 || digit < 0)
                        {
                            if (!throwException)
                            {
                                return(null);
                            }
                            else
                            {
                                throw new FormatException("Illegal character found");
                            }
                        }
                        // Multiply by 10
                        for (int j = 0; j < bn; ++j)
                        {
                            int p;
                            p = unchecked ((((int)bigint[j]) & ShortMask) * 10);
                            int p2 = ((int)carry) & ShortMask;
                            p         = unchecked (p + p2);
                            bigint[j] = unchecked ((short)p);
                            carry     = unchecked ((short)(p >> 16));
                        }
                    }
                    if (carry != 0)
                    {
                        bigint = EInteger.GrowForCarry(bigint, carry);
                    }
                    // Add the parsed digit
                    if (digit != 0)
                    {
                        int d = bigint[0] & ShortMask;
                        if (d <= overf)
                        {
                            bigint[0] = unchecked ((short)(d + digit));
                        }
                        else if (EInteger.IncrementWords(
                                     bigint,
                                     0,
                                     bigint.Length,
                                     (short)digit) != 0)
                        {
                            bigint = EInteger.GrowForCarry(bigint, (short)1);
                        }
                    }
                    bn = Math.Min(bigint.Length, bn + 1);
                }
            }
            else
            {
                var   haveSmallInt = true;
                int[] msi          = EInteger.MaxSafeInts;
                int   maxSafeInt   = msi[radix - 2];
                int   maxShortPlusOneMinusRadix = 65536 - radix;
                var   smallInt = 0;
                for (int i = index; i < endIndex; ++i)
                {
                    char c     = cs[i];
                    int  digit = (c >= 0x80) ? 36 : c2d[(int)c];
                    if (digit >= radix)
                    {
                        if (!throwException)
                        {
                            return(null);
                        }
                        else
                        {
                            throw new FormatException("Illegal character found");
                        }
                    }
                    if (haveSmallInt && smallInt < maxSafeInt)
                    {
                        smallInt = (smallInt * radix) + digit;
                    }
                    else
                    {
                        if (haveSmallInt)
                        {
                            bigint[0] = unchecked ((short)(smallInt &
                                                           ShortMask));
                            bigint[1] = unchecked ((short)((smallInt >> 16) &
                                                           ShortMask));
                            haveSmallInt = false;
                        }
                        // Multiply by the radix
                        short carry = 0;
                        int   n     = bigint.Length;
                        for (int j = 0; j < n; ++j)
                        {
                            int p;
                            p = unchecked ((((int)bigint[j]) & ShortMask) *
                                           radix);
                            int p2 = ((int)carry) & ShortMask;
                            p         = unchecked (p + p2);
                            bigint[j] = unchecked ((short)p);
                            carry     = unchecked ((short)(p >> 16));
                        }
                        if (carry != 0)
                        {
                            bigint = EInteger.GrowForCarry(bigint, carry);
                        }
                        // Add the parsed digit
                        if (digit != 0)
                        {
                            int d = bigint[0] & ShortMask;
                            if (d <= maxShortPlusOneMinusRadix)
                            {
                                bigint[0] = unchecked ((short)(d + digit));
                            }
                            else if (EInteger.IncrementWords(
                                         bigint,
                                         0,
                                         bigint.Length,
                                         (short)digit) != 0)
                            {
                                bigint = EInteger.GrowForCarry(bigint, (short)1);
                            }
                        }
                    }
                }
                if (haveSmallInt)
                {
                    bigint[0] = unchecked ((short)(smallInt & ShortMask));
                    bigint[1] = unchecked ((short)((smallInt >> 16) &
                                                   ShortMask));
                }
            }
            int count = EInteger.CountWords(bigint);

            return((count == 0) ? EInteger.Zero : new EInteger(
                       count,
                       bigint,
                       negative));
        }