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