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