?? gf2ex.cpp
字號:
#include <NTL/GF2EX.h>
#include <NTL/vec_vec_GF2.h>
#include <NTL/new.h>
NTL_START_IMPL
const GF2EX& GF2EX::zero()
{
static GF2EX z;
return z;
}
istream& operator>>(istream& s, GF2EX& x)
{
s >> x.rep;
x.normalize();
return s;
}
ostream& operator<<(ostream& s, const GF2EX& a)
{
return s << a.rep;
}
void GF2EX::normalize()
{
long n;
const GF2E* p;
n = rep.length();
if (n == 0) return;
p = rep.elts() + n;
while (n > 0 && IsZero(*--p)) {
n--;
}
rep.SetLength(n);
}
long IsZero(const GF2EX& a)
{
return a.rep.length() == 0;
}
long IsOne(const GF2EX& a)
{
return a.rep.length() == 1 && IsOne(a.rep[0]);
}
void GetCoeff(GF2E& x, const GF2EX& a, long i)
{
if (i < 0 || i > deg(a))
clear(x);
else
x = a.rep[i];
}
void SetCoeff(GF2EX& x, long i, const GF2E& a)
{
long j, m;
if (i < 0)
Error("SetCoeff: negative index");
if (NTL_OVERFLOW(i, 1, 0))
Error("overflow in SetCoeff");
m = deg(x);
if (i > m) {
/* careful: a may alias a coefficient of x */
long alloc = x.rep.allocated();
if (alloc > 0 && i >= alloc) {
GF2E aa = a;
x.rep.SetLength(i+1);
x.rep[i] = aa;
}
else {
x.rep.SetLength(i+1);
x.rep[i] = a;
}
for (j = m+1; j < i; j++)
clear(x.rep[j]);
}
else
x.rep[i] = a;
x.normalize();
}
void SetCoeff(GF2EX& x, long i, GF2 a)
{
if (i < 0)
Error("SetCoeff: negative index");
if (a == 1)
SetCoeff(x, i);
else
SetCoeff(x, i, GF2E::zero());
}
void SetCoeff(GF2EX& x, long i, long a)
{
if (i < 0)
Error("SetCoeff: negative index");
if ((a & 1) == 1)
SetCoeff(x, i);
else
SetCoeff(x, i, GF2E::zero());
}
void SetCoeff(GF2EX& x, long i)
{
long j, m;
if (i < 0)
Error("coefficient index out of range");
if (NTL_OVERFLOW(i, 1, 0))
Error("overflow in SetCoeff");
m = deg(x);
if (i > m) {
x.rep.SetLength(i+1);
for (j = m+1; j < i; j++)
clear(x.rep[j]);
}
set(x.rep[i]);
x.normalize();
}
void SetX(GF2EX& x)
{
clear(x);
SetCoeff(x, 1);
}
long IsX(const GF2EX& a)
{
return deg(a) == 1 && IsOne(LeadCoeff(a)) && IsZero(ConstTerm(a));
}
const GF2E& coeff(const GF2EX& a, long i)
{
if (i < 0 || i > deg(a))
return GF2E::zero();
else
return a.rep[i];
}
const GF2E& LeadCoeff(const GF2EX& a)
{
if (IsZero(a))
return GF2E::zero();
else
return a.rep[deg(a)];
}
const GF2E& ConstTerm(const GF2EX& a)
{
if (IsZero(a))
return GF2E::zero();
else
return a.rep[0];
}
void conv(GF2EX& x, const GF2E& a)
{
if (IsZero(a))
x.rep.SetLength(0);
else {
x.rep.SetLength(1);
x.rep[0] = a;
}
}
void conv(GF2EX& x, long a)
{
if (a & 1)
set(x);
else
clear(x);
}
void conv(GF2EX& x, GF2 a)
{
if (a == 1)
set(x);
else
clear(x);
}
void conv(GF2EX& x, const ZZ& a)
{
if (IsOdd(a))
set(x);
else
clear(x);
}
void conv(GF2EX& x, const GF2X& aa)
{
GF2X a = aa; // in case a aliases the rep of a coefficient of x
long n = deg(a)+1;
long i;
x.rep.SetLength(n);
for (i = 0; i < n; i++)
conv(x.rep[i], coeff(a, i));
}
void conv(GF2EX& x, const vec_GF2E& a)
{
x.rep = a;
x.normalize();
}
{
long da = deg(a);
long db = deg(b);
long minab = min(da, db);
long maxab = max(da, db);
x.rep.SetLength(maxab+1);
long i;
const GF2E *ap, *bp;
GF2E* xp;
for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts();
i; i--, ap++, bp++, xp++)
add(*xp, (*ap), (*bp));
if (da > minab && &x != &a)
for (i = da-minab; i; i--, xp++, ap++)
*xp = *ap;
else if (db > minab && &x != &b)
for (i = db-minab; i; i--, xp++, bp++)
*xp = *bp;
else
x.normalize();
}
void add(GF2EX& x, const GF2EX& a, const GF2E& b)
{
long n = a.rep.length();
if (n == 0) {
conv(x, b);
}
else if (&x == &a) {
add(x.rep[0], a.rep[0], b);
x.normalize();
}
else if (x.rep.MaxLength() == 0) {
x = a;
add(x.rep[0], a.rep[0], b);
x.normalize();
}
else {
// ugly...b could alias a coeff of x
GF2E *xp = x.rep.elts();
add(xp[0], a.rep[0], b);
x.rep.SetLength(n);
xp = x.rep.elts();
const GF2E *ap = a.rep.elts();
long i;
for (i = 1; i < n; i++)
xp[i] = ap[i];
x.normalize();
}
}
void add(GF2EX& x, const GF2EX& a, GF2 b)
{
if (a.rep.length() == 0) {
conv(x, b);
}
else {
if (&x != &a) x = a;
add(x.rep[0], x.rep[0], b);
x.normalize();
}
}
void add(GF2EX& x, const GF2EX& a, long b)
{
if (a.rep.length() == 0) {
conv(x, b);
}
else {
if (&x != &a) x = a;
add(x.rep[0], x.rep[0], b);
x.normalize();
}
}
void PlainMul(GF2EX& x, const GF2EX& a, const GF2EX& b)
{
long da = deg(a);
long db = deg(b);
if (da < 0 || db < 0) {
clear(x);
return;
}
if (&a == &b) {
sqr(x, a);
return;
}
long d = da+db;
const GF2E *ap, *bp;
GF2E *xp;
GF2EX la, lb;
if (&x == &a) {
la = a;
ap = la.rep.elts();
}
else
ap = a.rep.elts();
if (&x == &b) {
lb = b;
bp = lb.rep.elts();
}
else
bp = b.rep.elts();
x.rep.SetLength(d+1);
xp = x.rep.elts();
long i, j, jmin, jmax;
GF2X t, accum;
for (i = 0; i <= d; i++) {
jmin = max(0, i-db);
jmax = min(da, i);
clear(accum);
for (j = jmin; j <= jmax; j++) {
mul(t, rep(ap[j]), rep(bp[i-j]));
add(accum, accum, t);
}
conv(xp[i], accum);
}
x.normalize();
}
void sqr(GF2EX& x, const GF2EX& a)
{
long da = deg(a);
if (da < 0) {
clear(x);
return;
}
x.rep.SetLength(2*da+1);
long i;
for (i = da; i > 0; i--) {
sqr(x.rep[2*i], a.rep[i]);
clear(x.rep[2*i-1]);
}
sqr(x.rep[0], a.rep[0]);
x.normalize();
}
static
void PlainMul1(GF2X *xp, const GF2X *ap, long sa, const GF2X& b)
{
long i;
for (i = 0; i < sa; i++)
mul(xp[i], ap[i], b);
}
static inline
void q_add(GF2X& x, const GF2X& a, const GF2X& b)
// This is a quick-and-dirty add rotine used by the karatsuba routine.
// It assumes that the output already has enough space allocated,
// thus avoiding any procedure calls.
// WARNING: it also accesses the underlying WordVector representation
// directly...that is dirty!.
// It shaves a few percent off the running time.
{
_ntl_ulong *xp = x.xrep.elts();
const _ntl_ulong *ap = a.xrep.elts();
const _ntl_ulong *bp = b.xrep.elts();
long sa = ap[-1];
long sb = bp[-1];
long i;
if (sa == sb) {
for (i = 0; i < sa; i++)
xp[i] = ap[i] ^ bp[i];
i = sa-1;
while (i >= 0 && !xp[i]) i--;
xp[-1] = i+1;
}
else if (sa < sb) {
for (i = 0; i < sa; i++)
xp[i] = ap[i] ^ bp[i];
for (; i < sb; i++)
xp[i] = bp[i];
xp[-1] = sb;
}
else { // sa > sb
for (i = 0; i < sb; i++)
xp[i] = ap[i] ^ bp[i];
for (; i < sa; i++)
xp[i] = ap[i];
xp[-1] = sa;
}
}
static inline
void q_copy(GF2X& x, const GF2X& a)
// see comments for q_add above
{
_ntl_ulong *xp = x.xrep.elts();
const _ntl_ulong *ap = a.xrep.elts();
long sa = ap[-1];
long i;
for (i = 0; i < sa; i++)
xp[i] = ap[i];
xp[-1] = sa;
}
static
void KarFold(GF2X *T, const GF2X *b, long sb, long hsa)
{
long m = sb - hsa;
long i;
for (i = 0; i < m; i++)
q_add(T[i], b[i], b[hsa+i]);
for (i = m; i < hsa; i++)
q_copy(T[i], b[i]);
}
static
void KarAdd(GF2X *T, const GF2X *b, long sb)
{
long i;
for (i = 0; i < sb; i++)
q_add(T[i], T[i], b[i]);
}
static
void KarFix(GF2X *c, const GF2X *b, long sb, long hsa)
{
long i;
for (i = 0; i < hsa; i++)
q_copy(c[i], b[i]);
for (i = hsa; i < sb; i++)
q_add(c[i], c[i], b[i]);
}
static
void KarMul(GF2X *c, const GF2X *a,
long sa, const GF2X *b, long sb, GF2X *stk)
{
if (sa < sb) {
{ long t = sa; sa = sb; sb = t; }
{ const GF2X *t = a; a = b; b = t; }
}
if (sb == 1) {
if (sa == 1)
mul(*c, *a, *b);
else
PlainMul1(c, a, sa, *b);
return;
}
if (sb == 2 && sa == 2) {
mul(c[0], a[0], b[0]);
mul(c[2], a[1], b[1]);
q_add(stk[0], a[0], a[1]);
q_add(stk[1], b[0], b[1]);
mul(c[1], stk[0], stk[1]);
q_add(c[1], c[1], c[0]);
q_add(c[1], c[1], c[2]);
return;
}
long hsa = (sa + 1) >> 1;
if (hsa < sb) {
/* normal case */
long hsa2 = hsa << 1;
GF2X *T1, *T2, *T3;
T1 = stk; stk += hsa;
T2 = stk; stk += hsa;
T3 = stk; stk += hsa2 - 1;
/* compute T1 = a_lo + a_hi */
KarFold(T1, a, sa, hsa);
/* compute T2 = b_lo + b_hi */
KarFold(T2, b, sb, hsa);
/* recursively compute T3 = T1 * T2 */
KarMul(T3, T1, hsa, T2, hsa, stk);
/* recursively compute a_hi * b_hi into high part of c */
/* and subtract from T3 */
KarMul(c + hsa2, a+hsa, sa-hsa, b+hsa, sb-hsa, stk);
KarAdd(T3, c + hsa2, sa + sb - hsa2 - 1);
/* recursively compute a_lo*b_lo into low part of c */
/* and subtract from T3 */
KarMul(c, a, hsa, b, hsa, stk);
KarAdd(T3, c, hsa2 - 1);
clear(c[hsa2 - 1]);
/* finally, add T3 * X^{hsa} to c */
KarAdd(c+hsa, T3, hsa2-1);
}
else {
/* degenerate case */
GF2X *T;
T = stk; stk += hsa + sb - 1;
/* recursively compute b*a_hi into high part of c */
KarMul(c + hsa, a + hsa, sa - hsa, b, sb, stk);
/* recursively compute b*a_lo into T */
KarMul(T, a, hsa, b, sb, stk);
KarFix(c, T, hsa + sb - 1, hsa);
}
}
void ExtractBits(_ntl_ulong *cp, const _ntl_ulong *ap, long k, long n)
// extract k bits from a at position n
{
long sc = (k + NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG;
long wn = n/NTL_BITS_PER_LONG;
long bn = n - wn*NTL_BITS_PER_LONG;
long i;
if (bn == 0) {
for (i = 0; i < sc; i++)
cp[i] = ap[i+wn];
}
else {
for (i = 0; i < sc-1; i++)
cp[i] = (ap[i+wn] >> bn) | (ap[i+wn+1] << (NTL_BITS_PER_LONG - bn));
if ((k + n) % NTL_BITS_PER_LONG != 0)
cp[sc-1] = (ap[sc+wn-1] >> bn)|(ap[sc+wn] << (NTL_BITS_PER_LONG - bn));
else
cp[sc-1] = ap[sc+wn-1] >> bn;
}
long p = k % NTL_BITS_PER_LONG;
if (p != 0)
cp[sc-1] &= ((1UL << p) - 1UL);
}
void KronSubst(GF2X& aa, const GF2EX& a)
{
long sa = a.rep.length();
long blocksz = 2*GF2E::degree() - 1;
long saa = sa*blocksz;
long wsaa = (saa + NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG;
aa.xrep.SetLength(wsaa+1);
_ntl_ulong *paa = aa.xrep.elts();
long i;
for (i = 0; i < wsaa+1; i++)
paa[i] = 0;
for (i = 0; i < sa; i++)
ShiftAdd(paa, rep(a.rep[i]).xrep.elts(), rep(a.rep[i]).xrep.length(),
blocksz*i);
aa.normalize();
}
void KronMul(GF2EX& x, const GF2EX& a, const GF2EX& b)
{
if (a == 0 || b == 0) {
clear(x);
return;
}
GF2X aa, bb, xx;
long sx = deg(a) + deg(b) + 1;
long blocksz = 2*GF2E::degree() - 1;
if (NTL_OVERFLOW(blocksz, sx, 0))
Error("overflow in GF2EX KronMul");
KronSubst(aa, a);
KronSubst(bb, b);
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -