#include "radix.h"
int
radix_divmod_bn_karp_markstein(nn_ptr q, nn_ptr rem, nn_srcptr a, slong an,
nn_srcptr b, slong bn, slong n, const radix_t radix)
{
slong m, nm;
nn_ptr y, qf;
TMP_INIT;
FLINT_ASSERT(an >= 1);
FLINT_ASSERT(bn >= 1);
FLINT_ASSERT(n >= 1);
TMP_START;
m = (n + 1) / 2;
nm = n - m;
y = TMP_ALLOC(m * sizeof(ulong));
if (!radix_invmod_bn(y, b, bn, m, radix))
{
TMP_END;
return 0;
}
qf = TMP_ALLOC(n * sizeof(ulong));
radix_mulmid(qf, a, FLINT_MIN(an, m), y, m, 0, m, radix);
if (nm > 0)
{
nn_ptr bq0h, dh, scratch;
slong ah;
ulong bo;
scratch = TMP_ALLOC(n * sizeof(ulong));
bq0h = TMP_ALLOC(nm * sizeof(ulong));
_radix_mulhigh_known_low(bq0h, b, bn, qf, m, a, an, m, n, scratch, radix);
dh = TMP_ALLOC(nm * sizeof(ulong));
ah = (an > m) ? FLINT_MIN(an - m, nm) : 0;
bo = 0;
if (ah > 0)
bo = radix_sub(dh, a + m, ah, bq0h, ah, radix);
if (ah < nm)
{
radix_neg(dh + ah, bq0h + ah, nm - ah, radix);
if (bo)
radix_sub(dh + ah, dh + ah, nm - ah, &bo, 1, radix);
}
radix_mulmid(qf + m, y, m, dh, nm, 0, nm, radix);
}
if (rem != NULL)
{
nn_ptr prodh, scratch;
slong ac;
ulong bo;
scratch = TMP_ALLOC((n + bn) * sizeof(ulong));
prodh = TMP_ALLOC(bn * sizeof(ulong));
_radix_mulhigh_known_low(prodh, qf, n, b, bn, a, an, n, n + bn, scratch, radix);
ac = (an > n) ? FLINT_MIN(an - n, bn) : 0;
bo = 0;
if (ac > 0)
bo = radix_sub(rem, a + n, ac, prodh, ac, radix);
if (ac < bn)
{
radix_neg(rem + ac, prodh + ac, bn - ac, radix);
if (bo)
radix_sub(rem + ac, rem + ac, bn - ac, &bo, 1, radix);
}
}
flint_mpn_copyi(q, qf, n);
TMP_END;
return 1;
}