public uint [] Value; // array itself #region Constructors protected BigNumber() { Size = INIT_SIZE; Value = new uint[Size]; Spart = 1; Sign = signt.positive; }
protected BigNumber(ulong Val) { Size = INIT_SIZE; Value = new uint[Size]; Sign = signt.positive; ToBigInt(Val); }
protected BigNumber(short BitSize, ulong Val) { Size = BitSize; Value = new uint[Size]; Sign = Val >= 0 ? signt.positive : signt.negative; ulong AbsVal = Val; ToBigInt(AbsVal); }
protected BigNumber(long Val) { Size = INIT_SIZE; Value = new uint[Size]; Sign = Val >= 0 ? signt.positive : signt.negative; ulong AbsVal = (ulong)Math.Abs(Val); ToBigInt(AbsVal); }
public BigNumber(short BitSize, string Str) { Size = BitSize; Value = new uint[Size]; if (Str != null && Str.Length >= 1) { Sign = Str[0] == '-' ? signt.negative : signt.positive; } ToBigInt(Str); }
protected BigNumber(BigNumber bn, signt s) { Value = new uint[bn.Size]; Size = bn.Size; Spart = bn.Spart; Sign = s; for (int i = 0; i < Spart; i++) { Value[i] = bn.Value[i]; } }
public static string AsString(this signt sign) { switch (sign) { case signt.positive: return("+"); case signt.negative: return("-"); default: throw new ArgumentException(); } }
private static void _Mul(ref BigInt C, ref BigInt B1, ref BigInt B2, signt ResultSign) { ulong Tmp; B2 = (BigInt)B1.SameSize(B2); C.Resize((short)(2 * B1.Spart + 1)); for (int i = 0; i < B2.Spart; i++) { for (int j = 0; j < B1.Spart; j++) { ulong B1Val = B1.Value[j], B2Val = B2.Value[i]; Tmp = B1Val * B2Val; C.AddCell2((short)(i + j), Tmp); } } C.Sign = ResultSign; }
private static void _Add(ref BigInt C, BigInt B1, BigInt B2, signt ResultSign) { ulong Tmp, Over = 0; B2 = (BigInt)B1.SameSize(B2); C.Resize((short)(B1.Spart + 1)); for (int i = 0; i < B1.Spart; i++) { ulong B1Val = B1.Value[i], B2Val = B2.Value[i]; Tmp = B1Val + B2Val + Over; C.Value[i] = (uint)(Tmp & CELL_MASK); Over = (Tmp >> CELL_SIZE) & CELL_MASK; } C.Value[B1.Spart] = (uint)Over; C.Sign = ResultSign; }
protected BigNumber(short BitSize, uint[] Value) { Spart = (short)Value.Length; if (Spart > BitSize) { throw (new ArithmeticException($"Cell overflow in constructor. The length of the array should be less than {INIT_SIZE}.")); } Size = BitSize; this.Value = new uint[Size]; Sign = signt.positive; for (int i = Spart - 1, j = 0; i >= 0; i--, j++) { this.Value[j] = Value[i]; } Reduce(); }
private static void _MulKara(ref BigInt C, ref BigInt B1, ref BigInt B2, signt ResultSign) { short B1Spart = B1.Spart; short B2Spart = B2.Spart; B1.Reduce(); B2.Reduce(); B2 = (BigInt)B1.SameSize(B2); C.Resize((short)(2 * B1.Spart + 1)); if (B1.Spart <= SPART_LIMIT || ((B1Spart < SPART_LIMIT && (B2Spart - B1Spart) > SPART_LIMIT) || (B2Spart < SPART_LIMIT && (B1Spart - B2Spart) > SPART_LIMIT))) { _Mul(ref C, ref B1, ref B2, ResultSign); } else { B1.Reduce(); B2.Reduce(); short Part = B1.Spart < B2.Spart ? (short)(B1.Spart / 2) : (short)(B2.Spart / 2); //short PartCopy = Part; //while (PartCopy != 0 && PartCopy < (B1.Spart < B2.Spart ? B1.Spart : B2.Spart) && CELL_SIZE % PartCopy != 0) //{ // PartCopy++; //} //if (PartCopy != 0 && CELL_SIZE % PartCopy == 0) //{ // Part = PartCopy; //} //else //{ // PartCopy = Part; // while (PartCopy > 0 && CELL_SIZE % PartCopy != 0) // { // PartCopy--; // } // Part = PartCopy; //} B2 = (BigInt)B1.SameSize(B2); BigInt D = new BigInt(B1.Size, 0), E = new BigInt(B1.Size, 0); BigInt F = new BigInt(B1.Size, 0), G = new BigInt(B1.Size, 0); BigInt Z0 = new BigInt(B1.Size, 0), Z1 = new BigInt(B1.Size, 0), Z2 = new BigInt(B1.Size, 0); // C := Z2 * (Base ^ (2 * Part)) + (Z1 - Z2 - Z0) * (Base ^ Part) + Z0 B1.Split(ref D, ref E, Part); B2.Split(ref F, ref G, Part); // K = D + E // L = F + G BigInt K = D + E; BigInt L = F + G; // Z0 := E*G // Z1 := K*L // Z2 := D*F _MulKara(ref Z0, ref E, ref G, ResultSign); _MulKara(ref Z1, ref K, ref L, ResultSign); _MulKara(ref Z2, ref D, ref F, ResultSign); Z0.Reduce(); Z1.Reduce(); Z2.Reduce(); // Z2Copy = Z2 * (Base ^ (2 * Part)) BigInt Z2Copy = Z2.Clone(); for (int i = 0; i < 2 * Part; i++) { // Z2 * Base // Base = 2 ^ CELL_SIZE Z2Copy.ShiftLeft(CELL_SIZE); } // (Z1 - Z2 - Z0) * (Base ^ Part) BigInt ZDiff = Z1 - Z2 - Z0; for (int i = 0; i < Part; i++) { // ZDiff * Base // Base = 2 ^ CELL_SIZE ZDiff.ShiftLeft(CELL_SIZE); } C = Z2Copy + ZDiff + Z0; C.Reduce(); } }
public BigInt(BigInt bi, signt s) : base(bi, s) { }
private static void _DivCellMod(ref BigInt Q, ref BigInt R, BigInt B, uint DefaultBase, signt ResultSign) { uint[] Result = new uint[B.Size]; short ResultPos = 0; // First copy the Dividend (B) to the Remainder R B.Reduce(); R = B.Clone(); short Pos = (short)(R.Spart - 1); ulong Dividend = R.Value[Pos]; if (Dividend >= DefaultBase) { ulong LocalQuotient = Dividend / DefaultBase; Result[ResultPos++] = (uint)LocalQuotient; R.Value[Pos] = (uint)(Dividend % DefaultBase); } Pos--; while (Pos >= 0) { Dividend = ((ulong)R.Value[Pos + 1] << CELL_SIZE) + (ulong)R.Value[Pos]; ulong LocalQuotient = Dividend / DefaultBase; Result[ResultPos++] = (uint)LocalQuotient; R.Value[Pos + 1] = 0; R.Value[Pos--] = (uint)(Dividend % DefaultBase); } Q.Spart = ResultPos; int j = 0; for (int i = Q.Spart - 1; i >= 0; i--, j++) { Q.Value[j] = Result[i]; } for (; j < B.Size; j++) { Q.Value[j] = 0; } Q.Sign = ResultSign; Q.Reduce(); R.Reduce(); }
private static void _Divmod(ref BigInt Q, ref BigInt R, ref BigInt B1, ref BigInt B2, signt ResultSign) { B1.Reduce(); B2.Reduce(); // B1: Dividend and B2: Divisor short B1Spart = B1.Spart; short B2Spart = B2.Spart; Q = new BigInt(B1.Size, 0); // Q: Quotient R = new BigInt(B1, signt.positive); // R: Rest if (B2 == 0) { throw new ArithmeticException("Divide by zero"); } if (B1 == Q || B1Spart < B2Spart || B1 < B2) { Q.Sign = ResultSign; Q.Reduce(); R.Reduce(); } else if (B1 == B2) { Q = new BigInt(B1.Size, 1); Q.Sign = ResultSign; R = new BigInt(B1.Size, 0); } else if (B1Spart < 3 && B2Spart < 3) { // Process cell2-Division ulong Cell2Dividend = B1.Spart == 2 ? ((ulong)B1.Value[1] << CELL_SIZE) + B1.Value[0] : B1.Value[0]; ulong Cell2Divisor = B2.Spart == 2 ? ((ulong)B2.Value[1] << CELL_SIZE) + B2.Value[0] : B2.Value[0]; Q = new BigInt(B1.Size, Cell2Dividend / Cell2Divisor); R = new BigInt(B1.Size, Cell2Dividend % Cell2Divisor); } else if (B2Spart < 2) { B2.Reduce(); _DivCellMod(ref Q, ref R, B1, B2.Value[B2.Spart - 1], ResultSign); } else { B1.Reduce(); B2.Reduce(); uint[] Result = new uint[B1.Size]; int RemainderLength = B1.Spart + 1; uint[] Remainder = new uint[RemainderLength]; uint Mask = HIGH_BIT_MASK; uint Val = B2.Value[B2.Spart - 1]; int Shift = 0, ResultPos = 0; while (Mask != 0 && (Val & Mask) == 0) { Shift++; Mask >>= 1; } for (int i = 0; i < B1.Spart; i++) { Remainder[i] = B1.Value[i]; } ShiftLeft(Remainder, (short)Shift); B2.ShiftLeft((short)Shift); B2.Reduce(); int J = RemainderLength - B2.Spart; int Pos = RemainderLength - 1; ulong FirstDivisorCell = B2.Value[B2.Spart - 1]; ulong SecondDiviorCell = B2.Value[B2.Spart - 2]; int DivisorLength = B2.Spart + 1; uint[] DividendPart = new uint[DivisorLength]; while (J > 0) { ulong Dividend = ((ulong)Remainder[Pos] << CELL_SIZE) + (ulong)Remainder[Pos - 1]; ulong Q_hat = Dividend / FirstDivisorCell; ulong R_hat = Dividend % FirstDivisorCell; bool Done = false; while (!Done) { Done = true; if (Q_hat == MAX_CELL_VALUE || (Q_hat * SecondDiviorCell) > ((R_hat << CELL_SIZE) + Remainder[Pos - 2])) { Q_hat--; R_hat += FirstDivisorCell; if (R_hat < MAX_CELL_VALUE) { Done = false; } } } for (int h = 0; h < DivisorLength; h++) { DividendPart[h] = Remainder[Pos - h]; } BigInt K = new BigInt(B1.Size, DividendPart); BigInt S = B2 * Q_hat; //uint f = 1; //BigInt B2Divisor = B2.Clone(); while (S > K) { //Q_hat = Q_hat - f; //S = S - B2Divisor; Q_hat--; S -= B2; //f = f << 1; //B2Divisor.ShiftLeft(1); } //f = f >> 1; //B2Divisor.ShiftRigth(1); //Q_hat = Q_hat + f; //S = S + B2Divisor; BigInt Y = K - S; B2.Reduce(); for (int h = 0; h < DivisorLength; h++) { Remainder[Pos - h] = Y.Value[B2.Spart - h]; } Result[ResultPos++] = (uint)Q_hat; Pos--; J--; } Q.Spart = (short)ResultPos; int y = 0; for (int x = Q.Spart - 1; x >= 0; x--, y++) { Q.Value[y] = Result[x]; } for (; y < B1.Size; y++) { Q.Value[y] = 0; } Q.Reduce(); R.Spart = (short)ShiftRigth(Remainder, (short)Shift); for (y = 0; y < R.Spart; y++) { R.Value[y] = Remainder[y]; } for (; y < B1.Size; y++) { R.Value[y] = 0; } } R.Reduce(); //BigInt RCopy = R.Clone(); //int Cmp = Compare(B1, B2); //if (Cmp == -1 && B1.Sign == signt.negative && B2.Sign == signt.positive) //{ // RCopy.Sign = ResultSign; //} Q.Sign = ResultSign; BigInt B1E = Q * B2 + R; if (R != 0 && Compare(B1E, B1) != 0) { if (B2.Sign == signt.negative) { if (ResultSign == signt.positive) { Q++; } else { Q--; } } else if (B1.Sign == signt.negative) { if (ResultSign == signt.positive) { Q--; } else { Q++; } } } Q.Reduce(); }