#include "flint-mparam.h"
#include "ulong_extras.h"
#include "nmod_poly.h"
#include "nmod.h"
ulong
_nmod_poly_evaluate_nmod(nn_srcptr poly, slong len, ulong c, nmod_t mod)
{
slong m;
ulong val;
if (len == 0)
return 0;
if (len == 1 || c == 0)
return poly[0];
m = len - 1;
val = poly[m];
m--;
for ( ; m >= 0; m--)
{
val = nmod_mul(val, c, mod);
val = n_addmod(val, poly[m], mod.n);
}
return val;
}
ulong
_nmod_poly_evaluate_nmod_precomp(nn_srcptr poly, slong len, ulong c, ulong c_precomp, nmod_t mod)
{
slong m;
ulong val;
if (len == 0)
return 0;
if (len == 1 || c == 0)
return poly[0];
m = len - 1;
val = poly[m];
m--;
for ( ; m >= 0; m--)
{
val = n_mulmod_shoup(c, val, c_precomp, mod.n);
val = n_addmod(val, poly[m], mod.n);
}
return val;
}
ulong
_nmod_poly_evaluate_nmod_precomp_lazy(nn_srcptr poly, slong len, ulong c, ulong c_precomp, nmod_t mod)
{
slong m;
ulong val, p_hi, p_lo;
if (len == 0)
return 0;
if (len == 1 || c == 0)
return poly[0];
m = len - 1;
val = poly[m];
m--;
for ( ; m >= 0; m--)
{
umul_ppmm(p_hi, p_lo, c_precomp, val);
val = c * val - p_hi * mod.n;
val += poly[m];
}
if (val >= 2*mod.n)
return val - 2*mod.n;
if (val >= mod.n)
return val - mod.n;
return val;
}
ulong
nmod_poly_evaluate_nmod(const nmod_poly_t poly, ulong c)
{
if (poly->length == 0)
return 0;
if (poly->length == 1 || c == 0)
return poly->coeffs[0];
#if FLINT_MULMOD_SHOUP_THRESHOLD <= 2
if (poly->mod.norm == 0) #else
if ((poly->length < FLINT_MULMOD_SHOUP_THRESHOLD)
|| (poly->mod.norm == 0))
#endif
{
return _nmod_poly_evaluate_nmod(poly->coeffs, poly->length, c, poly->mod);
}
else
#if FLINT_BITS == 64
if (poly->mod.n <= UWORD(6148914691236517205))
#else
if (poly->mod.n <= UWORD(1431655765))
#endif
{
const ulong c_precomp = n_mulmod_precomp_shoup(c, poly->mod.n);
return _nmod_poly_evaluate_nmod_precomp_lazy(poly->coeffs, poly->length, c, c_precomp, poly->mod);
}
else
{
const ulong c_precomp = n_mulmod_precomp_shoup(c, poly->mod.n);
return _nmod_poly_evaluate_nmod_precomp(poly->coeffs, poly->length, c, c_precomp, poly->mod);
}
}