Mul(Digits a, int aN, Digits b, int bN, Digits c) { Debug.Assert(!c._Overlaps(a) && !c._Overlaps(b) , "overlapping arguments"); Digits p1, p2; int i, n1, n2; if (aN > bN) { p1 = a; p2 = b; n1 = aN; n2 = bN; } else { p2 = a; p1 = b; n2 = aN; n1 = bN; } if (n2 == 0) { Debug.Assert(false, "untested code"); c._SetAll(0, n1); return; } c[n1] = Mul(p1, p2[0], c, n1); for (i = 1; i != n2; i++) { c[i + n1] = Accumulate(p1, p2[i], c + i, n1); } }
static void Random(Digits mod, Digits arr, int n, Random generator) { Debug.Assert(!arr._Overlaps(mod), "overlapping arguments"); int sigDigitN = n; while (sigDigitN > 0 && mod[sigDigitN - 1] == 0) { Debug.Assert(false, "untested code"); arr[sigDigitN - 1] = 0; sigDigitN--; } if (sigDigitN == 0) { throw new ArgumentException(); } Digit nlead = mod[sigDigitN - 1]; int ntry = 0; do { ntry++; Debug.Assert(ntry <= 100, "too many iterations"); Digits.Random(arr, sigDigitN - 1, generator); arr[sigDigitN - 1] = Digit.Random(0, nlead, generator); } while (Digits.Compare(arr, mod, sigDigitN) >= 0); }
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); } }
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; } } }