1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
Copyright (C) 2010 William Hart
Copyright (C) 2024 Vincent Neiger
This file is part of FLINT.
FLINT is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. See <https://www.gnu.org/licenses/>.
*/
#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, ulong modn)
{
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, modn);
val = n_addmod(val, poly[m], modn);
}
return val;
}
ulong
_nmod_poly_evaluate_nmod_precomp_lazy(nn_srcptr poly, slong len, ulong c, ulong c_precomp, ulong modn)
{
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--)
{
// computes either val = (c*val mod n) or val = (c*val mod n) + n
// see documentation of ulong_extras / n_mulmod_shoup for details
umul_ppmm(p_hi, p_lo, c_precomp, val);
val = c * val - p_hi * modn;
// lazy addition, yields val in [0..k+2n-1), where max(poly) < k
// --> if k == n (poly is reduced mod n), constraint: 3n-1 <= 2**FLINT_BITS
val += poly[m];
}
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 degree below the n_mulmod_shoup threshold
// or modulus forbids n_mulmod_shoup usage, use nmod_mul
#if FLINT_MULMOD_SHOUP_THRESHOLD <= 2
if (poly->mod.norm == 0) // here poly->length >= threshold
#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);
}
// if 3*mod.n - 1 <= 2**FLINT_BITS, use n_mulmod_shoup, lazy variant
else
{
const ulong modn = poly->mod.n;
#if FLINT_BITS == 64
if (modn <= UWORD(6148914691236517205))
#else // FLINT_BITS == 32
if (modn <= UWORD(1431655765))
#endif
{
const ulong c_precomp = n_mulmod_precomp_shoup(c, modn);
ulong val = _nmod_poly_evaluate_nmod_precomp_lazy(poly->coeffs, poly->length, c, c_precomp, modn);
// correct excess
if (val >= 2*modn)
val -= 2*modn;
else if (val >= modn)
val -= modn;
return val;
}
// use n_mulmod_shoup, non-lazy variant
else
{
const ulong c_precomp = n_mulmod_precomp_shoup(c, modn);
return _nmod_poly_evaluate_nmod_precomp(poly->coeffs, poly->length, c, c_precomp, modn);
}
}
}