Sub(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]; int itest; if (alead == blead) { itest = Digits.Compare(a, b, n - 1); } else { itest = alead < blead ? -1 : +1; } if (itest < 0) { if (blead >= mlead) { ValidateData(b, mod, n); } int carry = Digits.AddSub(a, mod, b, c, n); Debug.Assert(carry == 0, "internal error"); } else { if (alead >= mlead) { Debug.Assert(false, "untested code"); ValidateData(a, mod, n); } uint borrow = Digits.Sub(a, b, c, n); Debug.Assert(borrow == 0, "internal error"); } }
static void Mul22U( Digit[] mat , Digits vec1 , Digits vec2 , int lvec , Digits carrys ) { Digit carry1 = 0, carry2 = 0; Digit m11 = mat[0], m12 = mat[1], m21 = mat[2], m22 = mat[3]; if (m12 > Digit.MaxValue - m11 || m21 > Digit.MaxValue - m22) { throw new ArgumentException(); } for (int i = 0; i != lvec; i++) { UInt64 prod11 = (UInt64)m11 * vec1[i] + carry1 , prod21 = (UInt64)m21 * vec1[i] + carry2 , prod12 = (UInt64)m12 * vec2[i] + Digit2.Lo(prod11) , prod22 = (UInt64)m22 * vec2[i] + Digit2.Lo(prod21); vec1[i] = Digit2.Lo(prod12); vec2[i] = Digit2.Lo(prod22); carry1 = Digit2.Hi(prod11) + Digit2.Hi(prod12); carry2 = Digit2.Hi(prod21) + Digit2.Hi(prod22); } carrys[0] = carry1; carrys[1] = carry2; }
Mul22S(Digit[] mat, Digits vec1, Digits vec2, int lvec, int[] carrys) { int carry1 = 0, carry2 = 0; Digit m11 = mat[0], m12 = mat[1], m21 = mat[2], m22 = mat[3]; if (((m11 | m12 | m21 | m22) & 1U << Digit.BitN - 1) != 0) { throw new ArgumentException(); } for (int i = 0; i != lvec; i++) { UInt64 prod11 = (UInt64)m11 * vec1[i] , prod12 = (UInt64)m12 * vec2[i] , prod21 = (UInt64)m21 * vec1[i] , prod22 = (UInt64)m22 * vec2[i] , prod1 = unchecked (prod11 + (UInt64)carry1) , prod2 = unchecked (prod22 + (UInt64)carry2); prod1 = unchecked (prod1 - prod12); prod2 = unchecked (prod2 - prod21); vec1[i] = Digit2.Lo(prod1); vec2[i] = Digit2.Lo(prod2); carry1 = unchecked ((int)Digit2.Hi(prod1)); carry2 = unchecked ((int)Digit2.Hi(prod2)); } carrys[0] = carry1; carrys[1] = carry2; }
internal static int Compare(Digits a, int aN, Digits b, int bN) { int la = aN, lb = bN; while (la > lb) { if (a[la - 1] != 0) { return(+1); } la--; } while (lb > la) { if (b[lb - 1] != 0) { return(-1); } lb--; } Debug.Assert(la == lb, "internal error"); while (la != 0) { if (a[la - 1] != b[la - 1]) { return(a[la - 1] > b[la - 1] ? +1 : -1); } la--; } return(0); }
internal void _Set(Digits from, int n) { for (int i = 0; i < n; i++) { this[i] = from[i]; } }
internal static bool DivisibleBySomeLowPrime(Digits digits, int n) { if (n == 0 || (digits[0] & 1) == 0) { Debug.Assert(false, "untested code"); return(true); } for (int l = 0; l != LowPrimesProduct.Length; l++) { Digit product = LowPrimesProduct[l] , productInverse = Digit.TwoAdicInverse(product) , r = 0; for (int i = 0; i != n; i++) { Digit mulby; unchecked { r += digits[i]; if (r < digits[i]) { r -= product; } mulby = productInverse * r; Debug.Assert(mulby * product == r, "internal error"); } r = product - Digit2.Hi((UInt64)mulby * product); } if (Digit.OddGcd(r, product) != 1) { return(true); } } return(false); }
internal static void Shift(Digits a, int shiftBitN, Digits b, int n) { int itranslate = shiftBitN >= 0 ? shiftBitN / Digit.BitN : -(-shiftBitN / Digit.BitN); ShiftLost(a, shiftBitN - Digit.BitN * itranslate, b, n); if (itranslate < 0) { Debug.Assert(false, "untested code"); int dtranslate = -itranslate; for (int i = 0; i != n; i++) { Debug.Assert(false, "untested code"); b[i] = i + dtranslate < n ? b[i + dtranslate] : 0; } } else if (itranslate > 0) { Debug.Assert(false, "untested code"); int dtranslate = itranslate; for (int i = n; i-- != 0;) { Debug.Assert(false, "untested code"); b[i] = i >= dtranslate ? b[i - dtranslate] : 0; } } }
BytesToDigits(byte[] bytes, int bytesI, Digits digits, int bitN) { if (bitN == 0) { Debug.Assert(false, "untested code"); return; } int digitN = (bitN + (Digit.BitN - 1)) / Digit.BitN; digits._SetAll(0, digitN); for (int iDigit = 0; iDigit != digitN; iDigit++) { int byteNLeft = (bitN + 7) / 8 - 4 * iDigit; Digit digit = 0; for ( int iByte = 0; iByte != (4 > byteNLeft ? byteNLeft : 4); iByte++ ) { digit ^= (Digit)bytes[bytesI + byteNLeft - 1 - iByte] << 8 * iByte; } digits[iDigit] = digit; } digits[digitN - 1] &= Digit.MaxValue >> Digit.BitN * digitN - bitN; }
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); } }
internal static void ValidateData(Digits data, Digits mod, int n) { if (Digits.Compare(data, mod, n) >= 0) { throw new ArgumentException(); } }
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); }
Random(Digits digits, int digitN, Random generator) { for (int i = 0; i < digitN; i++) { digits[i] = Digit.Random(generator); } }
static void Div( Digits numer , Digit den , Reciprocal recip , Digits q , int n , Digits r ) { Digit carry = 0; int nLeft = n; if (nLeft > 0 && numer[nLeft - 1] < den) { nLeft--; carry = numer[nLeft]; if (q != null) { q[nLeft] = 0; } } if (recip == null && nLeft < 2) { for (int i = nLeft; i-- != 0;) { Digit qest = 0; Digit2.Div((UInt64)carry << Digit.BitN | numer[i] , den , out qest , out carry); if (q != null) { q[i] = qest; } } } else { if (recip == null) { recip = new Reciprocal(); DivPrecondition(new Digits(new Digit[] { den }), 1, recip); } for (int i = nLeft; i-- != 0;) { Digit qest = 0; Digit2.Div((UInt64)carry << Digit.BitN | numer[i] , den , recip , out qest , out carry); if (q != null) { q[i] = qest; } } } r[0] = carry; }
void _MulFromLeft(Digits a, Digits b, Digits c) { Digits product = new Digits(2 * _digitN); Digits.Mul(a, _digitN, b, _digitN, product); Digits .Div(product, 2 * _digitN, _mod, _digitN, _leftRecip, null, c); }
internal void _Mul(Digits a, Digits b, Digits c) { Modular.ValidateData(a, _mod, _digitN); if (a != b) { Modular.ValidateData(b, _mod, _digitN); } _algorithm(a, b, c); }
static uint Add(Digits a, int aN, Digits b, int bN, Digits c) { if (aN < bN || aN < 0 || bN < 0) { throw new ArgumentException(); } uint carry = Add(a, b, c, bN); return(Add(a + bN, carry, c + bN, aN - bN)); }
internal static int SigDigitN(Digits a, int aN) { int i = aN; while (i != 0 && a[i - 1] == 0) { i--; } return(i); }
internal static int Compare(Digits a, Digits b, int n) { for (int i = n; i-- != 0;) { if (a[i] != b[i]) { return(a[i] > b[i] ? +1 : -1); } } return(0); }
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); }
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]))); }
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 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); }
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; } } }
void _BucketMul(UInt32 ibucket, Digits mult, Temps2000 temps) { Digits bloc = temps._bucket[ibucket]; if (temps._bucketBusy[ibucket]) { _Mul(bloc, mult, bloc); } else { temps._bucketBusy[ibucket] = true; bloc._Set(mult, _digitN); } }
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); }
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; }
NonZeroRandom(Digits mod, Digits arr, int n, Random generator) { if (Digits.Compare(mod, 1U, n) <= 0) { throw new ArgumentException(); } int ntry = 0; do { ntry++; Debug.Assert(ntry <= 100, "too many iterations"); Random(mod, arr, n, generator); } while (Digits.SigDigitN(arr, n) == 0); }
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 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(); } } }