internal static int SigBitN(Digit d) { d |= 1; int bitN = BitN; while (d < 1U << BitN - 5) { bitN -= 5; d <<= 5; } return(bitN - leadingZeroBitN[d >> BitN - 4]); }
internal static Digit Mul(Digits a, Digit mult, Digits b, int n) { Digit carry = 0; for (int i = 0; i != n; i++) { UInt64 dtemp = (UInt64)mult * a[i] + carry; b[i] = Digit2.Lo(dtemp); carry = Digit2.Hi(dtemp); } return(carry); }
internal static uint Sub(Digits a, Digits b, Digits c, int n) { uint borrow = 0; for (int i = 0; i != n; i++) { Digit ai = a[i], bi = b[i], sum = unchecked (ai - bi - borrow); c[i] = sum; borrow = (ai ^ (ai ^ bi | ai ^ sum)) >> Digit.BitN - 1; } return(borrow); }
Accumulate(Digits a, Digit mult, Digits b, int n) { Digit carry = 0; for (int i = 0; i != n; i++) { UInt64 dtemp = (UInt64)mult * a[i] + b[i] + carry; b[i] = Digit2.Lo(dtemp); carry = Digit2.Hi(dtemp); } return(carry); }
internal static int SigBitN(Digits a, int aN) { int sigDigitN = SigDigitN(a, aN); if (sigDigitN == 0) { Debug.Assert(false, "untested code"); return(0); } return((int)((sigDigitN - 1) * Digit.BitN + Digit.SigBitN(a[sigDigitN - 1]))); }
internal static uint Add(Digits a, Digits b, Digits c, int n) { uint carry = 0; for (int i = 0; i != n; i++) { Digit ai = a[i], bi = b[i], sum = unchecked (carry + (ai + bi)); c[i] = sum; carry = ((ai | bi) ^ (ai ^ bi) & sum) >> Digit.BitN - 1; } return(carry); }
DigitsToBytes(Digits digits, byte[] bytes, int byteI, int bitN) { for (int i = 0; i != (bitN + (Digit.BitN - 1)) / Digit.BitN; i++) { Digit dvalue = digits[i]; int byteNLeft = (bitN + 7) / 8 - 4 * i; for (int j = 0; j != (byteNLeft > 4 ? 4 : byteNLeft); j++) { bytes[byteI + byteNLeft - 1 - j] = (byte)(dvalue & 0xff); dvalue >>= 8; } } }
Div(UInt64 num, Digit denom, out Digit q, out Digit r) { Digit numHi = Hi(num), numLo = Lo(num); if (numHi >= denom) { throw new ArgumentException(); } q = (Digit)(num / denom); r = unchecked (numLo - denom * q); Digit rr = unchecked ((Digit)(num - denom * q)); Debug.Assert(rr == r, "internal error"); }
DivPrecondition(Digits denom, int denomN, Reciprocal recip) { if (denom == null) { throw new ArgumentNullException(); } if (denomN == 0 || denom[denomN - 1] == 0) { throw new ArgumentException(); } int recipBitShift = Digit.BitN - Digit.SigBitN(denom[denomN - 1]); Digit dlead2 = denom[denomN - 1] , dlead1 = denomN >= 2 ? denom[denomN - 2] : 0 , dlead0 = denomN >= 3 ? denom[denomN - 3] : 0 , dShiftHi = dlead2 << recipBitShift | dlead1 >> 1 >> Digit.BitN - 1 - recipBitShift , dShiftLo = dlead1 << recipBitShift | dlead0 >> 1 >> Digit.BitN - 1 - recipBitShift; Digit recipMpy, r; Digit2.Div((UInt64)(Digit.MaxValue - dShiftHi) << Digit.BitN | Digit.MaxValue - dShiftLo , dShiftHi , out recipMpy , out r); if (Digit2.Hi((UInt64)recipMpy * dShiftLo) > r) { recipMpy -= 1; } r = (Digit.MaxValue >> recipBitShift) - denom[denomN - 1]; for (int id = denomN; id-- != 0 && r < recipMpy;) { UInt64 test1 = (UInt64)r << Digit.BitN | Digit.MaxValue - (id > 0 ? denom[id - 1] : 0) , test2 = (UInt64)recipMpy * denom[id]; if (test2 > test1) { recipMpy -= 1; break; } test1 = test1 - test2; r = Digit2.Lo(test1); if (Digit2.Hi(test1) != 0) { break; } } recip._shiftBitN = recipBitShift; recip._multiplier = recipMpy; }
void _MulFromRight(Digits a, Digits b, Digits c) { Digit minv = _rightRecip , minva0 = unchecked (minv * a[0]) , mul1 = b[0] , mul2 = unchecked (minva0 * mul1) , carry1 = Digit2.Hi((UInt64)mul1 * a[0]) , carry2 = Digit2.Hi((UInt64)mul2 * _mod[0]); UInt64 prod1, prod2; Debug.Assert(unchecked (mul1 * a[0]) == unchecked (mul2 * _mod[0]) , "internal error"); Digits temp1 = new Digits(_digitN), temp2 = new Digits(_digitN); for (int i = 1; i != _digitN; i++) { prod1 = (UInt64)mul1 * a[i] + carry1; prod2 = (UInt64)mul2 * _mod[i] + carry2; temp1[i - 1] = Digit2.Lo(prod1); temp2[i - 1] = Digit2.Lo(prod2); carry1 = Digit2.Hi(prod1); carry2 = Digit2.Hi(prod2); } temp1[_digitN - 1] = carry1; temp2[_digitN - 1] = carry2; for (int j = 1; j != _digitN; j++) { mul1 = b[j]; mul2 = unchecked (minva0 * mul1 + minv * (temp1[0] - temp2[0])); prod1 = (UInt64)mul1 * a[0] + temp1[0]; prod2 = (UInt64)mul2 * _mod[0] + temp2[0]; Debug.Assert(Digit2.Lo(prod1) == Digit2.Lo(prod2) , "internal error"); carry1 = Digit2.Hi(prod1); carry2 = Digit2.Hi(prod2); for (int i = 1; i != _digitN; i++) { prod1 = (UInt64)mul1 * a[i] + temp1[i] + carry1; prod2 = (UInt64)mul2 * _mod[i] + temp2[i] + carry2; temp1[i - 1] = Digit2.Lo(prod1); temp2[i - 1] = Digit2.Lo(prod2); carry1 = Digit2.Hi(prod1); carry2 = Digit2.Hi(prod2); } temp1[_digitN - 1] = carry1; temp2[_digitN - 1] = carry2; } Modular.Sub(temp1, temp2, c, _mod, _digitN); }
Decumulate(Digits a, Digit mult, Digits b, int n) { Digit borrow = 0; for (int i = 0; i != n; i++) { UInt64 dtemp; unchecked { dtemp = (UInt64)b[i] - borrow - (UInt64)mult * a[i]; } b[i] = Digit2.Lo(dtemp); unchecked { borrow = 0 - Digit2.Hi(dtemp); } } return(borrow); }
internal Digit EstQuotient(Digit n2, Digit n1, Digit n0) { Digit nShiftHi = n2 << _shiftBitN | n1 >> 1 >> Digit.BitN - 1 - _shiftBitN , nShiftLo = n1 << _shiftBitN | n0 >> 1 >> Digit.BitN - 1 - _shiftBitN; UInt64 qprod = ((UInt64)nShiftHi << Digit.BitN | nShiftLo) + (UInt64)nShiftHi * _multiplier; if ((nShiftLo & 1U << Digit.BitN - 1) != 0) { qprod += _multiplier >> 1; } return(Digit2.Hi(qprod)); }
internal static void Neg(Digits a, Digits b, Digits mod, int n) { Digit allZero = 0; for (int i = 0; i != n; i++) { allZero |= a[i]; b[i] = a[i]; } if (allZero != 0) { if (Digits.Sub(mod, b, b, n) != 0) { throw new ArgumentException(); } } }
AddSub(Digits a, Digits b, Digits c, Digits d, int n) { uint carry1 = 0, carry2 = 0; for (int i = 0; i != n; i++) { Digit ai = a[i] , bi = b[i] , ci = c[i] , sum1 = unchecked (ai + bi + carry1) , sum2 = unchecked (sum1 - ci - carry2); d[i] = sum2; carry1 = (sum1 ^ (sum1 ^ ai | sum1 ^ bi)) >> Digit.BitN - 1; carry2 = (sum1 ^ (sum1 ^ ci | sum1 ^ sum2)) >> Digit.BitN - 1; } return((int)carry1 - (int)carry2); }
internal static uint Add(Digits a, Digit immediate, Digits b, int n) { uint carry = immediate; for (int i = 0; i != n; i++) { Digit bi = a[i] + carry; b[i] = bi; if (bi >= carry) { if (a != b) { (b + i + 1)._Set(a + i + 1, n - i - 1); } return(0); } carry = 1; } return(carry); }
internal static Digit TwoAdicInverse(Digit d) { if ((d & 1) == 0) { throw new ArgumentException(); } UInt32 dInverse = unchecked (3 * d ^ 2) , error = unchecked (1 - d * dInverse); Debug.Assert((error & 31) == 0, "internal error"); for (int bitN = 5; bitN < BitN / 2; bitN *= 2) { unchecked { dInverse += dInverse * error; error = error * error; Debug.Assert(error == 1 - d * dInverse, "internal error"); } } return(unchecked (dInverse * error + dInverse)); }
internal static int Sub(Digits a, Digit isub, Digits b, int n) { Digit borrow = isub; for (int i = 0; i != n; i++) { Digit ai = a[i]; b[i] = ai - borrow; if (ai >= borrow) { if (a != b) { (b + i + 1)._Set(a + i + 1, n - i - 1); } return(0); } borrow = 1; } return((int)borrow); }
void _Shift(Digits a, int n, Digits b) { if (a != b) { b._Set(a, _digitN); } Modular.ValidateData(a, _mod, _digitN); if (n < 0 && (_mod[0] & 1) == 0) { throw new ArgumentException(); } while (n > 0) { int shiftNow = n > Digit.BitN ? Digit.BitN : n; Digit carryOut = Digits.ShiftLost(b, shiftNow, b, _digitN) , qest = _leftRecip .EstQuotient(carryOut , b[_digitN - 1] , _digitN >= 2 ? b[_digitN - 2] : 0); carryOut -= Digits.Decumulate(_mod, qest, b, _digitN); if (carryOut != 0 || Digits.Compare(b, _mod, _digitN) >= 0) { carryOut -= Digits.Sub(b, _mod, b, _digitN); } Debug.Assert(carryOut == 0, "internal error"); n -= shiftNow; } while (n < 0) { int shiftNow = -n > Digit.BitN ? Digit.BitN : -n; Digit mul = unchecked (0 - _rightRecip * b[0]) & Digit.MaxValue >> Digit.BitN - shiftNow , carry = Digits.Accumulate(_mod, mul, b, _digitN) , lowBitNLost = Digits.ShiftLost(b, -shiftNow, b, _digitN); b[_digitN - 1] |= carry << Digit.BitN - shiftNow; Debug.Assert(lowBitNLost == 0, "internal error"); n += shiftNow; } }
Add(Digits a, Digits b, Digits c, Digits mod, int n) { Debug.Assert(n != 0, "internal error"); Digit alead = a[n - 1], blead = b[n - 1], mlead = mod[n - 1]; if (alead >= mlead) { ValidateData(a, mod, n); } if (blead >= mlead) { ValidateData(b, mod, n); } int test; if (blead > mlead - alead) { test = +1; } else if (mlead - alead - blead > 1) { test = -1; } else { test = Digits.CompareSum(a, b, mod, n); } if (test >= 0) { int carry = Digits.AddSub(a, b, mod, c, n); Debug.Assert(carry == 0, "internal error"); } else { uint carry = Digits.Add(a, b, c, n); Debug.Assert(carry == 0, "internal error"); } }
internal static void Div( UInt64 num , Digit denom , Reciprocal recip , out Digit q , out Digit r ) { Digit numHi = Hi(num) , numLo = Lo(num) , qEst = Digit.MaxValue - recip.EstQuotient(numHi, numLo, 0); UInt64 rEst = unchecked ( ((UInt64)(numHi - denom) << Digit.BitN | numLo) + (UInt64)qEst * denom ); q = unchecked ((Digit)(Hi(rEst) - qEst)); r = unchecked (Lo(rEst) + (denom & Hi(rEst))); Digit qq, rr; Div(num, denom, out qq, out rr); Debug.Assert(qq == q && rr == r, "internal error"); }
internal static int CompareSum(Digits a, Digits b, Digits c, int n) { int sumPrev = 0; for (int i = n; i-- != 0;) { Digit aval = a[i] , bval = b[i] , cval = c[i] , sumNow = unchecked (aval + bval); Debug.Assert(sumPrev == 0 || sumPrev == -1, "internal error"); sumPrev += (sumNow < aval ? 1 : 0) - (sumNow < cval ? 1 : 0); unchecked { sumNow -= cval; } if ( sumPrev != unchecked ((int)(uint)sumNow) || unchecked (sumPrev + 3 & 2) == 0 ) { return((sumPrev + 2 & 2) - 1); } } return(sumPrev); }
internal static Digit Hi(UInt64 x) { Digit hi = unchecked ((UInt32)(x >> Digit.BitN)); return(hi); }
LehmerMat22(UInt64 lead0orig, UInt64 lead1orig, Digit[] mat22) { Digit lead0h = Digit2.Hi(lead0orig) , lead0l = Digit2.Lo(lead0orig) , lead1h = Digit2.Hi(lead1orig) , lead1l = Digit2.Lo(lead1orig); bool progress = true; Digit m00 = 1, m01 = 0, m10 = 0, m11 = 1; Debug.Assert(lead0h != 0 && lead1h != 0 && ((lead0h | lead1h) & 1U << Digit.BitN - 1) != 0 , "internal error"); while (progress) { progress = false; if (lead0h - 1 > lead1h && lead0h != 0) { if (lead0h >> 2 >= lead1h + 2) { Digit q = lead0h / (lead1h + 2); UInt64 prod10By11 = (UInt64)q * (m10 + m11) , prod1l = (UInt64)q * lead1l; Debug.Assert(q > 3, "internal error"); if ( Digit2.Hi(prod10By11) == 0 && Digit2.Lo(prod10By11) <= Digit.MaxValue / 2 - m00 - m01 ) { Digit prod10 = q * m10; progress = true; lead0h -= (Digit)((long)(UInt32)q * lead1h + Digit2.Hi(prod1l) + (Digit2.Lo(prod1l) > lead0l ? 1L : 0L)); unchecked { lead0l -= Digit2.Lo(prod1l); } m00 += prod10; m01 += Digit2.Lo(prod10By11) - prod10; Debug.Assert((m00 | m01) < 1U << Digit.BitN - 1 , "internal error"); } } else { Digit overflowTest; do { m00 += m10; m01 += m11; overflowTest = (m00 | m01) & 1U << Digit.BitN - 1; lead0h -= lead1h + (lead1l > lead0l ? 1U : 0U); unchecked { lead0l -= lead1l; } } while (overflowTest == 0 && lead0h >= lead1h + 2); progress = true; if (overflowTest != 0) { progress = false; m00 -= m10; m01 -= m11; } } } if (lead1h - 1 > lead0h && lead1h != 0) { if (lead1h >> 2 >= lead0h + 2) { Digit q = lead1h / (lead0h + 2); UInt64 prod00And01 = (UInt64)q * (m00 + m01) , prod0l = (UInt64)q * lead0l; Debug.Assert(q > 3, "internal error"); if ( Digit2.Hi(prod00And01) == 0 && Digit2.Lo(prod00And01) <= Digit.MaxValue / 2 - m10 - m11 ) { Digit prod00 = q * m00; progress = true; lead1h -= q * lead0h + Digit2.Hi(prod0l) + (Digit2.Lo(prod0l) > lead1l ? 1U : 0U); unchecked { lead1l -= Digit2.Lo(prod0l); } m10 += prod00; m11 += Digit2.Lo(prod00And01) - prod00; Debug.Assert((m10 | m11) < 1U << Digit.BitN - 1 , "internal error"); } } else { Digit overflowTest; do { m10 += m00; m11 += m01; overflowTest = (m10 | m11) & 1U << Digit.BitN - 1; lead1h -= lead0h + (lead0l > lead1l ? 1U : 0U); unchecked { lead1l -= lead0l; } } while (overflowTest == 0 && lead1h >= lead0h + 2); progress = true; if (overflowTest != 0) { progress = false; m10 -= m00; m11 -= m01; } } } } Debug.Assert(((m00 | m01 | m10 | m11) & 1U << Digit.BitN - 1) == 0 , "internal error"); mat22[0] = m00; mat22[1] = m01; mat22[2] = m10; mat22[3] = m11; }
internal static int Compare(Digits a, Digit ivalue, int aN) { return(Compare(a, aN, new Digits(new Digit[] { ivalue }), 1)); }
internal Modulus(Digits mod, int digitN, bool fromRight) { if (digitN == 0 || mod[digitN - 1] == 0) { throw new ArgumentException(); } _mod = mod; _digitN = digitN; _fromRight = fromRight; _one = new Digits(digitN); _multiplier1 = new Digits(digitN); _multiplier2 = new Digits(digitN); // this.mod.Set(this.mod, _digitN); _leftRecip = new Reciprocal(); Digits.DivPrecondition(mod, digitN, _leftRecip); Digit mod0inv = 0; if ((mod[0] & 1) != 0) { mod0inv = Digit.TwoAdicInverse(mod[0]); } _rightRecip = mod0inv; int digitN2 = (digitN + 1) / 2; Digits temp = new Digits(digitN + digitN2); if (!fromRight) { _algorithm = new MulAlgorithm(_MulFromLeft); int dividendN = digitN + digitN2; _scaleBitN = 0; for (int i = 0; i != dividendN; i++) { temp[i] = Digit.MaxValue; } temp[dividendN - 1] = Digit.MaxValue >> _leftRecip._shiftBitN; Digits q = new Digits(digitN2 + 1); Digits r = new Digits(digitN); Digits.Div(temp, dividendN, mod, digitN, _leftRecip, q, r); Debug.Assert(q[digitN2] == 1, "internal error"); Digits.Add(r, 1U, r, digitN); Digits.Sub(mod, r, r, digitN); } else { _algorithm = new MulAlgorithm(_MulFromRight); _scaleBitN = Digit.BitN * digitN; if (mod0inv == 0) { throw new ArgumentException(); } _multiplier2[0] = mod0inv; temp[digitN] = Digits.Mul(mod, mod0inv, temp, digitN); Debug.Assert(temp[0] == 1, "internal error"); for (int i = 1; i != digitN2; i++) { Digit mul = unchecked (0 - mod0inv * temp[i]); _multiplier2[i] = mul; temp[i + digitN] = Digits.Accumulate(mod, mul, temp + i, digitN); Debug.Assert(temp[i] == 0, "internal error"); } _multiplier1._Set(temp + digitN2, digitN); } _ToModular(new Digits(new Digit[] { 1 }), 1, _one); }
_Exp(Digits @base, Digits exp, int expDigitN, Digits answer) { int expBitNUsed = Digits.SigBitN(exp, expDigitN); ushort[] widthCutoffs = new ushort[] { 6, 24, 80, 240, 672 }; Digits basepower = answer; int bucketWidth = 1; while ( bucketWidth < 5 && widthCutoffs[bucketWidth - 1] < expBitNUsed ) { bucketWidth++; } Modular.ValidateData(@base, _mod, _digitN); UInt32 bucketMask = (1U << bucketWidth) - 1; UInt32 maxBucket = bucketMask; Digits bucketData = new Digits((int)(_digitN * maxBucket)); Temps2000 temps = new Temps2000(); temps._modulus = this; temps._bucket[0] = null; Modular.Add(_one, _one, bucketData, _mod, _digitN); bool base2 = Digits.Compare(@base, bucketData, _digitN) == 0; if (base2 && expBitNUsed != 0) { int shiftMax = Digit.BitN * _digitN > 1024 ? 1024 : Digit.BitN * _digitN; int highExponBitN = 0; bool bighBitNProcessed = false; Digits temp = bucketData; for (int i = expBitNUsed; i-- != 0;) { Digit expBit = Digits.GetBit(exp, i); if (bighBitNProcessed) { _Mul(temp, temp, temp); if (expBit != 0) { Modular.Add(temp, temp, temp, _mod, _digitN); } } else { highExponBitN = (int)(2 * highExponBitN + expBit); if (i == 0 || 2 * highExponBitN >= shiftMax) { bighBitNProcessed = true; _Shift(_one, highExponBitN, temp); } } } temps._bucket[1] = temp; Debug.Assert(bighBitNProcessed, "internal error"); } else { UInt32 ibucket; for (ibucket = 1; ibucket <= maxBucket; ibucket++) { Digits bloc = bucketData + (int)(_digitN * (ibucket - 1 + ((ibucket & 1) == 0 ? maxBucket : 0)) / 2); temps._bucket[ibucket] = bloc; temps._bucketBusy[ibucket] = false; bloc._Set(_one, _digitN); } basepower._Set(@base, _digitN); Digit carried = 0; int ndoubling = 0; for (int i = 0; i != expBitNUsed; i++) { Digit bitNow = Digits.GetBit(exp, i); Debug.Assert(carried >> bucketWidth + 2 == 0 , "internal error"); if (bitNow != 0) { while (ndoubling >= bucketWidth + 1) { if ((carried & 1) != 0) { ibucket = carried & bucketMask; carried -= ibucket; temps._modulus ._BucketMul(ibucket, basepower, temps); } temps._modulus._BasePowerSquaring(basepower); carried /= 2; ndoubling--; } carried |= 1U << ndoubling; } ndoubling++; } while (carried != 0) { bool squareNow = false; if (carried <= maxBucket) { ibucket = carried; } else if ((carried & 1) == 0) { squareNow = true; } else if (carried <= 3 * maxBucket) { ibucket = maxBucket; } else { Debug.Assert(false, "untested code"); ibucket = carried & bucketMask; } if (squareNow) { carried /= 2; temps._modulus._BasePowerSquaring(basepower); } else { carried -= ibucket; temps._modulus._BucketMul(ibucket, basepower, temps); } } for (ibucket = maxBucket; ibucket >= 2; ibucket--) { if (temps._bucketBusy[ibucket]) { bool found = false; UInt32 jbucket, jbucketMax, kbucket; Digits bloci; if ((ibucket & 1) == 0) { jbucketMax = ibucket / 2; } else { jbucketMax = 1; } for ( jbucket = ibucket >> 1; jbucket != ibucket && !found; jbucket++ ) { if (temps._bucketBusy[jbucket]) { jbucketMax = jbucket; found = temps._bucketBusy[ibucket - jbucket]; } } jbucket = jbucketMax; kbucket = ibucket - jbucket; bloci = temps._bucket[ibucket]; temps._modulus._BucketMul(jbucket, bloci, temps); temps._modulus._BucketMul(kbucket, bloci, temps); } } } answer._Set(temps._bucket[1], _digitN); }
internal static void ExtendedGcd( Digits a , int aN , Digits b , int bN , Digits ainvmodb , Digits binvmoda , Digits gcd , out int lgcd ) { Debug.Assert(!gcd._Overlaps(a) && !gcd._Overlaps(b) && !ainvmodb._Overlaps(a) && !ainvmodb._Overlaps(b) && !ainvmodb._Overlaps(gcd) , "overlapping arguments"); int aSigDigitN = SigDigitN(a, aN), bSigDigitN = SigDigitN(b, bN); if (aSigDigitN == 0 || bSigDigitN == 0) { throw new ArgumentException(); } int[] abN = new int[2] { aSigDigitN, bSigDigitN }; if (a == null || b == null || gcd == null || ainvmodb == null) { throw new ArgumentNullException(); } int maxDigitN = aN > bN ? aN : bN; Digits ab0Padded = new Digits(maxDigitN + 2) , ab1Padded = new Digits(maxDigitN + 2) , tempProd = new Digits(2 * maxDigitN) , tempQ = new Digits(maxDigitN + 1); Digits[] ab = new Digits[] { ab0Padded + 1, ab1Padded + 1 }; ab[0]._Set(a, aSigDigitN); ab[1]._Set(b, bSigDigitN); Digits[] tempsMul = new Digits[] { new Digits(maxDigitN), new Digits(maxDigitN) }; tempsMul[0][0] = 1; int mulN = 1, iterations = 0; while (abN[0] != 0 && abN[1] != 0) { int abN0 = abN[0], abN1 = abN[1]; Digits pab0top = ab[0] + (abN0 - 1) , pab1top = ab[1] + (abN1 - 1); Digit topword0 = pab0top[0], topword1 = pab1top[0]; int topsigbitN0 = Digit.SigBitN(topword0) , topsigbitN1 = Digit.SigBitN(topword1) , sigbitN0 = Digit.BitN * (abN0 - 1) + topsigbitN0 , sigbitN1 = Digit.BitN * (abN1 - 1) + topsigbitN1 , maxSigBitN = sigbitN0 > sigbitN1 ? sigbitN0 : sigbitN1 , maxlab = abN0 > abN1 ? abN0 : abN1 , ibig = Compare(ab[1], abN1, ab[0], abN0) > 0 ? 1 : 0 , ismall = 1 - ibig; Digit[] mat22 = new Digit[4]; iterations++; Debug.Assert(iterations <= Digit.BitN * (aN + bN + 1) , "too many iterations"); if (maxlab == 1) { Digit ab0, ab1, m00, m01, m10, m11; if (topword0 > Digit.MaxValue - topword1) { if (ibig == 0) { topword0 -= topword1; } else { topword1 -= topword0; } Digit carry = Add(tempsMul[0] , tempsMul[1] , tempsMul[ibig] , mulN); if (carry != 0) { Debug.Assert(false, "untested code"); Debug.Assert(mulN < bN, "internal error"); tempsMul[ibig][mulN] = carry; mulN++; } } ab0 = topword0; ab1 = topword1; m00 = 1; m01 = 0; m10 = 0; m11 = 1; while (ab1 != 0) { if (ab0 >= ab1) { if (ab0 >> 2 >= ab1) { Digit q = ab0 / ab1; ab0 -= q * ab1; m00 += q * m10; m01 += q * m11; } else { do { ab0 -= ab1; m00 += m10; m01 += m11; } while (ab0 >= ab1); } } Debug.Assert(ab1 > ab0, "internal error"); if (ab0 == 0) { break; } if (ab1 >> 2 >= ab0) { Digit q = ab1 / ab0; ab1 -= q * ab0; m10 += q * m00; m11 += q * m01; } else { do { ab1 -= ab0; m10 += m00; m11 += m01; } while (ab1 >= ab0); } Debug.Assert(ab0 > ab1, "internal error"); } ab[0][0] = ab0; ab[1][0] = ab1; abN[0] = ab0 != 0 ? 1 : 0; abN[1] = ab1 != 0 ? 1 : 0; mat22[0] = m00; mat22[1] = m01; mat22[2] = m10; mat22[3] = m11; Digits carrys = new Digits(2); Mul22U(mat22, tempsMul[0], tempsMul[1], mulN, carrys); if (carrys[0] == 0 && carrys[1] == 0) { } else { Debug.Assert(mulN < bN, "internal error"); tempsMul[0][mulN] = carrys[0]; tempsMul[1][mulN] = carrys[1]; mulN++; } } else if ( sigbitN0 > sigbitN1 + Digit.BitN / 2 || sigbitN1 > sigbitN0 + Digit.BitN / 2 ) { int smallMulN = SigDigitN(tempsMul[ismall], mulN); Div(ab[ibig] , abN[ibig] , ab[ismall] , abN[ismall] , null , tempQ , tempProd); int lQ = SigDigitN(tempQ, abN[ibig] - abN[ismall] + 1); abN[ibig] = SigDigitN(tempProd, abN[ismall]); ab[ibig]._Set(tempProd, abN[ibig]); Mul(tempQ, lQ, tempsMul[ismall], smallMulN, tempProd); AddFull(tempProd , SigDigitN(tempProd, lQ + smallMulN) , tempsMul[ibig] , mulN , tempsMul[ibig] , out mulN); } else { int norm = (int)(Digit.BitN * maxlab - maxSigBitN); pab0top[1] = pab1top[1] = 0; Debug.Assert(maxlab >= 2, "internal error"); UInt64 lead0 = (UInt64) (ab[0][maxlab - 1] << norm | ab[0][maxlab - 2] >> 1 >> Digit.BitN - 1 - norm) << Digit.BitN | (ab[0][maxlab - 2] << norm | ab[0][maxlab - 3] >> 1 >> Digit.BitN - 1 - norm) , lead1 = (UInt64) (ab[1][maxlab - 1] << norm | ab[1][maxlab - 2] >> 1 >> Digit.BitN - 1 - norm) << Digit.BitN | (ab[1][maxlab - 2] << norm | ab[1][maxlab - 3] >> 1 >> Digit.BitN - 1 - norm); LehmerMat22(lead0, lead1, mat22); if ((mat22[1] | mat22[2]) == 0) { Debug.Assert(false, "untested code"); Debug.Assert( mat22[0] == 1 && mat22[3] == 1, "internal error"); mat22[ibig + 1] = 1; } int lab = abN0 > abN1 ? abN0 : abN1; int[] scarrys = new int[2]; Mul22S(mat22, ab[0], ab[1], lab, scarrys); Debug.Assert(scarrys[0] == 0 && scarrys[1] == 0 , "internal error"); int abN0Sig = lab, abN1Sig = lab; while (abN0Sig != 0 && ab[0][abN0Sig - 1] == 0) { abN0Sig--; } while (abN1Sig != 0 && ab[1][abN1Sig - 1] == 0) { abN1Sig--; } abN[0] = abN0Sig; abN[1] = abN1Sig; Digits carrys = new Digits(2); Mul22U(mat22, tempsMul[0], tempsMul[1], mulN, carrys); if (carrys[0] == 0 && carrys[1] == 0) { } else { Debug.Assert(mulN < bN, "internal error"); tempsMul[0][mulN] = carrys[0]; tempsMul[1][mulN] = carrys[1]; mulN++; } } } Digit igcd = (Digit)(abN[0] == 0 ? 1U : 0U); lgcd = abN[igcd]; gcd._Set(ab[igcd], lgcd); Debug.Assert(Compare(b, tempsMul[1 - igcd], bN) >= 0 && Compare(tempsMul[1 - igcd], tempsMul[igcd], bN) >= 0 , "internal error"); if (igcd == 0) { ainvmodb._Set(tempsMul[0], bN); } else { Sub(tempsMul[0], tempsMul[1], ainvmodb, bN); } if (binvmoda != null) { Sub(tempsMul[1 - igcd], ainvmodb, tempsMul[1 - igcd], bN); Mul(a, aN, tempsMul[1 - igcd], bN, tempProd); Add(tempProd, aN + bN, gcd, lgcd, tempProd); Div(tempProd , aN + bSigDigitN , b , bSigDigitN , null , tempQ , tempsMul[1 - igcd]); Debug.Assert(SigDigitN(tempsMul[1 - igcd], bSigDigitN) == 0 , "internal error"); binvmoda._Set(tempQ, aN); } }
ShiftLost(Digits a, int bitScale, Digits b, int n) { if (n == 0) { Debug.Assert(false, "untested code"); return(0); } if (bitScale == 0) { Debug.Assert(false, "untested code"); b._Set(a, n); return(0); } Digit bitNLost = 0; if (bitScale > 0) { if (bitScale > Digit.BitN) { throw new ArgumentException(); } if (bitScale == Digit.BitN) { bitNLost = a[n - 1]; for (int i = n - 1; i != 0; i--) { b[i] = a[i - 1]; } b[0] = 0; } else { for (int i = 0; i != n; i++) { Digit bNew = a[i] << bitScale | bitNLost; bitNLost = a[i] >> Digit.BitN - bitScale; b[i] = bNew; } } } else { if (bitScale < -Digit.BitN) { throw new ArgumentException(); } if (bitScale == -Digit.BitN) { bitNLost = a[0]; for (int i = 1; i != n; i++) { b[i - 1] = a[i]; } b[n - 1] = 0; } else { for (int i = n; i-- != 0;) { Digit bNew = a[i] >> -bitScale | bitNLost; bitNLost = a[i] << Digit.BitN + bitScale; b[i] = bNew; } bitNLost >>= Digit.BitN + bitScale; } } return(bitNLost); }
internal static void Div( Digits num , int numN , Digits denom , int denomN , Reciprocal recip , Digits q , Digits r ) { if (denomN == 0) { throw new DivideByZeroException(); } if (num == null || denom == null || r == null) { throw new ArgumentNullException(); } Debug.Assert(!r._Overlaps(num) && !r._Overlaps(denom) , "overlapping arguments"); if (q != null) { Debug.Assert( !q._Overlaps(num) && !q._Overlaps(denom) && !r._Overlaps(q) , "overlapping arguments" ); } Digit dlead = denom[denomN - 1]; if (dlead == 0) { throw new ArgumentException(); } if (numN < denomN) { Debug.Assert(false, "untested code"); Set(num, numN, r, denomN); return; } if (denomN == 1) { Div(num, dlead, recip, q, numN, r); return; } if (recip == null) { recip = new Reciprocal(); DivPrecondition(denom, denomN, recip); } r[denomN - 1] = 0; r._Set(num + (numN - denomN + 1), denomN - 1); for (int iq = numN - denomN + 1; iq-- != 0;) { Digit rTop = r[denomN - 1]; for (int i = denomN - 1; i != 0; i--) { r[i] = r[i - 1]; } r[0] = num[iq]; Digit qest; if (rTop == 0 && Compare(r, denom, denomN) < 0) { qest = 0; } else { qest = recip.EstQuotient(rTop, r[denomN - 1], r[denomN - 2]); if (qest < Digit.MaxValue) { qest += 1; } Digit borrow = Decumulate(denom, qest, r, denomN); if (borrow > rTop) { qest -= 1; borrow -= Add(r, denom, r, denomN); } Debug.Assert(borrow == rTop, "internal error"); } if (q != null) { q[iq] = qest; } } }