public static QAndMod bdiv(uint[] a, uint[] b)
{
var n = a.Length - 1;
var t = b.Length - 1;
var nmt = n - t;
// trivial cases; a < b
if (n < t || n == t && (a[n] < b[n] || n > 0 && a[n] == b[n] && a[n - 1] < b[n - 1]))
{
return new QAndMod { q = new uint[] { 0 }, mod = a };
}
// trivial cases; q < 4
if (n == t && toppart(a, t, 2) / toppart(b, t, 2) < 4)
{
var tx = a.ToArray();
uint qq = 0;
uint[] xx;
for (; ; )
{
xx = bsub(tx, b);
if (xx.Length == 0) break;
tx = xx; qq++;
}
return new QAndMod { q = new uint[] { qq }, mod = tx };
}
// normalize
int shift2 = (int)Math.Floor(Math.Log(b[t]) / log2) + 1;
int shift = bs - shift2;
var x = a.ToArray();
var y = b.ToArray();
if (shift != 0)
{
for (int i = t; i > 0; i--) y[i] = (uint)(((y[i] << shift) & bm) | (y[i - 1] >> shift2));
y[0] = (uint)((y[0] << shift) & bm);
if ((x[n] & ((bm << shift2) & bm)) != 0)
{
x[++n] = 0; nmt++;
}
for (int i = n; i > 0; i--) x[i] = (uint)(((x[i] << shift) & bm) | (x[i - 1] >> shift2));
x[0] = (uint)((x[0] << shift) & bm);
}
int j;
uint[] x2;
var q = new uint[nmt + 1];
var y2 = new uint[nmt].Concat(y);
for (; ; )
{
x2 = bsub(x, y2);
if (x2.Length == 0) break;
q[nmt]++;
x = x2;
}
var yt = y[t];
var top = toppart(y, t, 2);
for (int i = n; i > t; i--)
{
var m = i - t - 1;
if (i >= x.Length) q[m] = 1;
else if (x[i] == yt) q[m] = (uint)bm;
else q[m] = (uint)((double)toppart(x, i, 2) / (double)yt);
var topx = toppart(x, i, 3);
while (q[m] * top > topx) q[m]--;
//x-=q[m]*y*b^m
y2 = y2.Slice(1);
x2 = bsub(x, bmul(new uint[] { q[m] }, y2));
if (x2.Length == 0)
{
q[m]--;
x2 = bsub(x, bmul(new uint[] { q[m] }, y2));
}
x = x2;
}
// de-normalize
if (shift != 0)
{
for (int i = 0; i < x.Length - 1; i++) x[i] = (uint)((x[i] >> shift) | ((x[i + 1] << shift2) & bm));
x[x.Length - 1] >>= shift;
}
return new QAndMod { q = zclip(q), mod = zclip(x) };
}