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); }