internal static Number FastPower(Number a, LongIntegerNumber b)
 {
     Number re = One;
     while(b != Zero) {
         if(b.parts.First() % 2 == 1)
             re = re * a;
         a = (a * a);
         b = b.IntDivide(Two);
     }
     return b.isNegative ? (One / re) : re;
 }
 Number AddCore(LongIntegerNumber longNumber)
 {
     return new LongIntegerNumber(AddImpl(this.parts, longNumber.parts, isNegative, longNumber.isNegative), false);
 }
        static int FindDigit(LongIntegerNumber divident, IList<int> divisorParts)
        {
            LongIntegerNumber divisor = new LongIntegerNumber(divisorParts, false);
            if(divident == Zero || divisor > divident) {
                return 0;
            }
            int dividentPart = ((divident.parts.Count == divisor.parts.Count) ? divident.parts.Last() : divident.parts.Last() * BaseFull + divident.parts[divident.parts.Count - 2]);
            int divisorPart = divisor.parts.Last();
            int lowDigit = Div(dividentPart, divisorPart + 1); //TODO optimize - no need to add 1 if divisor has zeros at the end
            #if DEBUG
            int checkCount = 0;
            #endif
            int topDigit = Div(dividentPart + 1, divisorPart);
            int digit = Bisect(lowDigit, topDigit);
            while(true) {
                Number mult = divisor.Multiply(new LongIntegerNumber(new int[] { digit }, false));
                LongIntegerNumber remain = (LongIntegerNumber)divident.Subtract(mult);
                if(remain.isNegative) {
            #if DEBUG
                    checkCount++;
            #endif
                    topDigit = digit;
                    digit = Bisect(lowDigit, topDigit);
                    continue;
                }
                int comparisonResult = remain.Compare(divisor);
                if(comparisonResult >= 0) {
            #if DEBUG
                    checkCount++;
            #endif
                    lowDigit = digit + 1;
                    digit = Bisect(lowDigit, topDigit);
                    continue;
                }
                break;
            }
            #if DEBUG
            if(checkCount > 15)
                throw new InvalidOperationException();
            #endif

            return digit;
        }
 static IList<int> DivieImpl(IList<int> dividentParts, IList<int> originalDivisor, out LongIntegerNumber remain)
 {
     remain = new LongIntegerNumber(dividentParts, false);
     IList<int> divisor = new List<int>(originalDivisor);
     int shiftCount = 0;
     while(CompareCore(remain.parts, divisor) >= 0) {
         ShiftLeft(divisor);
         shiftCount++;
     }
     ShiftRight(divisor);
     shiftCount--;
     List<int> result = new List<int>();
     while(divisor.Count >= originalDivisor.Count) {
         int digit = FindDigit(remain, divisor);
         result.Insert(0, digit);
         Number temp = (new LongIntegerNumber(divisor, false)).Multiply(new LongIntegerNumber(new int[] { digit }, false));
         remain = (LongIntegerNumber)remain.Subtract(temp);
         if(CompareCore(remain.parts, divisor) < 0)
             ShiftRight(divisor);
     }
     return result;
 }
        static int Compare(LongIntegerNumber n1, LongIntegerNumber n2)
        {
            if(!n1.parts.Any() && !n2.parts.Any())
                return 0;
            if(!n2.parts.Any())
                return n1.isNegative ? -1 : 1;
            if(!n1.parts.Any())
                return n2.isNegative ? 1 : -1;

            if(n1.isNegative && !n2.isNegative)
                return -1;
            if(!n1.isNegative && n2.isNegative)
                return 1;
            int partsComparisonResult = CompareCore(n1.parts, n2.parts);
            return n1.isNegative ? -partsComparisonResult : partsComparisonResult;
        }
 protected override Number Add(Number n)
 {
     var longNumber = n.ConvertCast<LongIntegerNumber>();
     if(!isNegative && !longNumber.isNegative)
         return AddCore(longNumber);
     if(longNumber.isNegative) {
         var invertedRight = new LongIntegerNumber(longNumber.parts, false);
         if(this < invertedRight)
             return new LongIntegerNumber(invertedRight.Subtract(this).ConvertCast<LongIntegerNumber>().parts, true);
     } else {
         var invertedLeft = new LongIntegerNumber(this.parts, false);
         if(longNumber < invertedLeft)
             return new LongIntegerNumber(invertedLeft.Subtract(longNumber).ConvertCast<LongIntegerNumber>().parts, true);
     }
     return AddCore(longNumber);
 }