#include "radix.h"
#define RADIX_LSH_DIVREM(hi, lo, x, be2, pre) \
do { \
if ((pre)->m == 0) \
(hi) = n_divrem_precomp_m0(&(lo), (x), (be2), (pre)); \
else if ((pre)->c == 0) \
(hi) = n_divrem_precomp_c0(&(lo), (x), (be2), (pre)); \
else \
(hi) = n_divrem_precomp_c1_bounded(&(lo), (x), (be2), (pre)); \
} while (0)
ulong
radix_addlsh(nn_ptr res, nn_srcptr a, slong an, nn_srcptr b, slong bn,
unsigned int sh, const radix_t radix)
{
ulong cy, hi, lo, B = LIMB_RADIX(radix);
ulong be = radix->bpow[sh];
ulong be2 = radix->bpow[radix->exp - sh];
n_div_precomp_t pre;
ulong shcy = 0, sb, qh, rl;
slong i, L;
FLINT_ASSERT(sh >= 1 && sh < radix->exp);
FLINT_ASSERT(bn >= 1);
*pre = radix->bpow_div[radix->exp - sh];
L = FLINT_MAX(an, bn + 1);
cy = 0;
cy -= 1;
for (i = 0; i < L; i++)
{
if (i < bn)
{
RADIX_LSH_DIVREM(qh, rl, b[i], be2, pre);
sb = shcy + rl * be;
shcy = qh;
}
else if (i == bn)
{
sb = shcy;
}
else
{
sb = 0;
}
{
ulong ai = (i < an) ? a[i] : 0;
sub_ddmmss(hi, lo, 0, ai + (cy + 1), 0, B - sb);
res[i] = lo + (hi & B);
cy = hi;
}
}
cy += 1;
return cy;
}
ulong
radix_sublsh(nn_ptr res, nn_srcptr a, slong an, nn_srcptr b, slong bn,
unsigned int sh, const radix_t radix)
{
ulong cy, hi, lo, B = LIMB_RADIX(radix);
ulong be = radix->bpow[sh];
ulong be2 = radix->bpow[radix->exp - sh];
n_div_precomp_t pre;
ulong shcy = 0, sb, qh, rl;
slong i, L;
FLINT_ASSERT(sh >= 1 && sh < radix->exp);
FLINT_ASSERT(bn >= 1);
*pre = radix->bpow_div[radix->exp - sh];
L = FLINT_MAX(an, bn + 1);
cy = 0;
for (i = 0; i < L; i++)
{
if (i < bn)
{
RADIX_LSH_DIVREM(qh, rl, b[i], be2, pre);
sb = shcy + rl * be;
shcy = qh;
}
else if (i == bn)
{
sb = shcy;
}
else
{
sb = 0;
}
{
ulong ai = (i < an) ? a[i] : 0;
sub_ddmmss(hi, lo, 0, ai, 0, sb - cy);
res[i] = lo + (hi & B);
cy = hi;
}
}
return -cy;
}
ulong
radix_lshsub(nn_ptr res, nn_srcptr b, slong bn, unsigned int sh,
nn_srcptr a, slong an, const radix_t radix)
{
ulong cy, hi, lo, B = LIMB_RADIX(radix);
ulong be = radix->bpow[sh];
ulong be2 = radix->bpow[radix->exp - sh];
n_div_precomp_t pre;
ulong shcy = 0, sb, qh, rl;
slong i, L;
FLINT_ASSERT(sh >= 1 && sh < radix->exp);
FLINT_ASSERT(bn >= 1);
*pre = radix->bpow_div[radix->exp - sh];
L = FLINT_MAX(an, bn + 1);
cy = 0;
for (i = 0; i < L; i++)
{
if (i < bn)
{
RADIX_LSH_DIVREM(qh, rl, b[i], be2, pre);
sb = shcy + rl * be;
shcy = qh;
}
else if (i == bn)
{
sb = shcy;
}
else
{
sb = 0;
}
{
ulong ai = (i < an) ? a[i] : 0;
sub_ddmmss(hi, lo, 0, sb, 0, ai - cy);
res[i] = lo + (hi & B);
cy = hi;
}
}
return -cy;
}
int
radix_cmplsh(nn_srcptr a, slong an, nn_srcptr b, slong bn, unsigned int sh,
const radix_t radix)
{
ulong be = radix->bpow[sh];
ulong be2 = radix->bpow[radix->exp - sh];
n_div_precomp_t pre;
ulong qh, rl, sblo, sbhi, sb, alimb;
slong byn, j;
FLINT_ASSERT(sh >= 1 && sh < radix->exp);
if (bn == 0)
return (an == 0) ? 0 : 1;
if (an == 0)
return -1;
*pre = radix->bpow_div[radix->exp - sh];
RADIX_LSH_DIVREM(qh, rl, b[bn - 1], be2, pre);
byn = bn + (qh != 0);
if (an != byn)
return (an < byn) ? -1 : 1;
for (j = byn - 1; j >= 0; j--)
{
if (j < bn)
{
RADIX_LSH_DIVREM(qh, rl, b[j], be2, pre);
sblo = rl * be;
}
else
sblo = 0;
if (j - 1 >= 0 && j - 1 < bn)
{
RADIX_LSH_DIVREM(sbhi, rl, b[j - 1], be2, pre);
}
else
sbhi = 0;
sb = sblo + sbhi;
alimb = a[j];
if (alimb != sb)
return (alimb < sb) ? -1 : 1;
}
return 0;
}