private static void DivModUnsigned(uint[] u, uint[] v, out uint[] q, out uint[] r) {
int m = GetLength(u);
int n = GetLength(v);
if (n <= 1) {
if (n == 0) {
throw new DivideByZeroException();
}
// Divide by single digit
//
ulong rem = 0;
uint v0 = v[0];
q = new uint[m];
r = new uint[1];
for (int j = m - 1; j >= 0; j--) {
rem *= Base;
rem += u[j];
ulong div = rem / v0;
rem -= div * v0;
q[j] = (uint)div;
}
r[0] = (uint)rem;
} else if (m >= n) {
int shift = GetNormalizeShift(v[n - 1]);
uint[] un = new uint[m + 1];
uint[] vn = new uint[n];
Normalize(u, m, un, shift);
Normalize(v, n, vn, shift);
q = new uint[m - n + 1];
r = null;
TestDivisionStep(un, vn, q, u, v);
// Main division loop
//
for (int j = m - n; j >= 0; j--) {
ulong rr, qq;
int i;
rr = Base * un[j + n] + un[j + n - 1];
qq = rr / vn[n - 1];
rr -= qq * vn[n - 1];
Debug.Assert((Base * un[j + n] + un[j + n - 1]) == qq * vn[n - 1] + rr);
for (; ; ) {
// Estimate too big ?
//
if ((qq >= Base) || (qq * vn[n - 2] > (rr * Base + un[j + n - 2]))) {
qq--;
rr += (ulong)vn[n - 1];
if (rr < Base) continue;
}
break;
}
Debug.Assert((Base * un[j + n] + un[j + n - 1]) == qq * vn[n - 1] + rr);
// Multiply and subtract
//
long b = 0;
long t = 0;
for (i = 0; i < n; i++) {
ulong p = vn[i] * qq;
t = (long)un[i + j] - (long)(uint)p - b;
un[i + j] = (uint)t;
p >>= 32;
t >>= 32;
Debug.Assert(t == 0 || t == -1 || t == -2);
b = (long)p - t;
}
t = (long)un[j + n] - b;
un[j + n] = (uint)t;
// Store the calculated value
//
q[j] = (uint)qq;
// Add back vn[0..n] to un[j..j+n]
//
if (t < 0) {
q[j]--;
ulong c = 0;
for (i = 0; i < n; i++) {
c = (ulong)vn[i] + un[j + i] + c;
un[j + i] = (uint)c;
c >>= 32;
}
c += (ulong)un[j + n];
un[j + n] = (uint)c;
}
TestDivisionStep(un, vn, q, u, v);
}
Unnormalize(un, out r, shift);
// Test normalized value ... Call TestNormalize
// only pass the values in different order.
//
TestNormalize(r, un, shift);
} else {
q = new uint[] { 0 };
r = u;
}
TestResult(u, v, q, r);
}