📄 poly2.cpp
字号:
/*
* C++ class to implement a polynomial type and to allow
* arithmetic on polynomials whose elements are from
* the finite field GF(2^m)
*
* WARNING: This class has been cobbled together for a specific use with
* the MIRACL library. It is not complete, and may not work in other
* applications
*
* See Knuth The Art of Computer Programming Vol.2, Chapter 4.6
*/
#include "poly2.h"
Poly2::Poly2(const GF2m& c,int p)
{
start=NULL;
addterm(c,p);
}
Poly2::Poly2(Variable &x)
{
start=NULL;
addterm((GF2m)1,1);
}
Poly2 operator*(const GF2m& c,Variable x)
{
Poly2 t(c,1);
return t;
}
Poly2& Poly2::operator=(const GF2m& m)
{
clear();
if (!m.iszero()) addterm(m,0);
return *this;
}
Poly2 pow2(Variable x,int n)
{
Poly2 r((GF2m)1,n);
return r;
}
Poly2::Poly2(const Poly2& p)
{
term2 *ptr=p.start;
term2 *pos=NULL;
start=NULL;
while (ptr!=NULL)
{
pos=addterm(ptr->an,ptr->n,pos);
ptr=ptr->next;
}
}
Poly2::~Poly2()
{
term2 *nx;
while (start!=NULL)
{
nx=start->next;
delete start;
start=nx;
}
}
GF2m Poly2::coeff(int power) const
{
GF2m c=0;
term2 *ptr=start;
while (ptr!=NULL)
{
if (ptr->n==power)
{
c=ptr->an;
return c;
}
ptr=ptr->next;
}
return c;
}
GF2m Poly2::F(const GF2m& x) const
{
GF2m f=0;
int diff;
term2 *ptr=start;
// Horner's rule
if (ptr==NULL) return f;
f=ptr->an;
while (ptr->next!=NULL)
{
diff=ptr->n-ptr->next->n;
if (diff==1) f=f*x+ptr->next->an;
else f=f*pow(x,diff)+ptr->next->an;
ptr=ptr->next;
}
f*=pow(x,ptr->n);
return f;
}
GF2m Poly2:: min() const
{
term2 *ptr=start;
if (start==NULL) return (GF2m)0;
while (ptr->next!=NULL) ptr=ptr->next;
return (ptr->an);
}
Poly2 operator*(const Poly2& a,const Poly2& b)
{
int i,d,dega,degb,deg;
GF2m t;
Poly2 prod;
term2 *iptr,*pos;
term2 *ptr=b.start;
if (&a==&b)
{ // squaring - only diagonal terms count!
pos=NULL;
while (ptr!=NULL)
{ // diagonal terms
pos=prod.addterm(ptr->an*ptr->an,ptr->n+ptr->n,pos);
ptr=ptr->next;
}
return prod;
}
dega=degree(a);
deg=dega;
degb=degree(b);
if (degb<dega) deg=degb; // deg is smallest
if (deg>=KARAT_BREAK_EVEN)
{ // use fast method
int len,m,inc;
big *A,*B,*C,*T;
deg=dega;
if (dega<degb) deg=degb; // deg is biggest
m=deg; inc=1;
while (m!=0) { m/=2; inc++; }
len=2*(deg+inc);
A=(big *)mr_alloc(deg+1,sizeof(big));
B=(big *)mr_alloc(deg+1,sizeof(big));
C=(big *)mr_alloc(len,sizeof(big));
T=(big *)mr_alloc(len,sizeof(big));
char *memc=(char *)memalloc(len);
char *memt=(char *)memalloc(len);
for (i=0;i<len;i++)
{
C[i]=mirvar_mem(memc,i);
T[i]=mirvar_mem(memt,i);
}
ptr=a.start;
while (ptr!=NULL)
{
A[ptr->n]=getbig(ptr->an);
ptr=ptr->next;
}
ptr=b.start;
while (ptr!=NULL)
{
B[ptr->n]=getbig(ptr->an);
ptr=ptr->next;
}
karmul2_poly(deg+1,T,A,B,C);
pos=NULL;
for (d=dega+degb;d>=0;d--)
{
t=C[d];
if (t.iszero()) continue;
pos=prod.addterm(t,d,pos);
}
memkill(memc,len);
memkill(memt,len);
mr_free(T);
mr_free(C);
mr_free(B);
mr_free(A);
return prod;
}
while (ptr!=NULL)
{
pos=NULL;
iptr=a.start;
while (iptr!=NULL)
{
pos=prod.addterm(ptr->an*iptr->an,ptr->n+iptr->n,pos);
iptr=iptr->next;
}
ptr=ptr->next;
}
return prod;
}
Poly2& Poly2::operator%=(const Poly2& v)
{
GF2m m,pq;
int power;
term2 *rptr=start;
term2 *vptr=v.start;
term2 *ptr,*pos;
if (degree(*this)<degree(v)) return *this;
m=((GF2m)1/vptr->an);
while (rptr!=NULL && rptr->n>=vptr->n)
{
pq=rptr->an*m;
power=rptr->n-vptr->n;
pos=NULL;
ptr=v.start;
while (ptr!=NULL)
{
pos=addterm(ptr->an*pq,ptr->n+power,pos);
ptr=ptr->next;
}
rptr=start;
}
return *this;
}
Poly2 operator%(const Poly2& u,const Poly2& v)
{
Poly2 r=u;
r%=v;
return r;
}
Poly2 fulldiv(Poly2& r,const Poly2 &v)
{
Poly2 q;
GF2m pq,m;
int power;
term2 *rptr=r.start;
term2 *vptr=v.start;
term2 *ptr,*pos;
m=(GF2m)1/vptr->an;
while (rptr!=NULL && rptr->n>=vptr->n)
{
pq=rptr->an*m;
power=rptr->n-vptr->n;
q.addterm(pq,power);
pos=NULL;
ptr=v.start;
while (ptr!=NULL)
{
pos=r.addterm(ptr->an*pq,ptr->n+power,pos);
ptr=ptr->next;
}
rptr=r.start;
}
return q;
}
Poly2 operator/(const Poly2& u,const Poly2 &v)
{
Poly2 r=u;
return fulldiv(r,v);
}
void swap(Poly2 &x,Poly2 &y)
{
term2 *t;
t=x.start;
x.start=y.start;
y.start=t;
}
void makemonic(Poly2& p)
{
term2 *ptr = p.start;
p.multerm((GF2m)1/ptr->an,0);
}
// A function to differentiate a polynomial
Poly2 differentiate(const Poly2& orig)
{
Poly2 newpoly;
term2 *ptr = orig.start;
term2 *pos = NULL;
int power;
while (ptr!=NULL)
{
power = ptr->n;
if(ptr->n > 0)
pos = newpoly.addterm(ptr->an*(GF2m)(power % 2),ptr->n-1,pos);
ptr = ptr->next;
}
return newpoly;
}
GF2m resultant(const Poly2& a,const Poly2 &b)
{ // borrowed from NTL
GF2m lc,r=1;
int d0,d1,d2;
if (iszero(a) || iszero(b)) return (GF2m)0;
if (degree(a)==0 && degree(b)==0) return (GF2m)1;
Poly2 u=a;
Poly2 v=b;
term2 *ptr;
forever
{
d0=degree(u);
d1=degree(v);
lc=v.coeff(d1);
u%=v;
ptr=v.start; v.start=u.start; u.start=ptr; // swap them
d2=degree(v);
if (!iszero(v))
{
lc=pow(lc,d0-d2);
r*=lc;
if (d0&d1&1) r=-r;
}
else
{
if (d1==0)
{
lc=pow(lc,d0);
r*=lc;
}
else r=0;
break;
}
}
return r;
}
Poly2 operator-(const Poly2& a,const GF2m& z)
{
Poly2 p=a;
p.addterm((z),0);
return p;
}
Poly2 operator-(const Poly2& a)
{
Poly2 p=a;
return p;
}
Poly2 operator-(const Poly2& a,const Poly2& b)
{
Poly2 sum;
sum=a;
sum+=b;
return sum;
}
Poly2 inverse(const Poly2& f,const Poly2& m)
{
Poly2 r,s,q,p,x;
term2 *ptr;
x=f%m;
r=1;
s=0;
p=m;
while (!iszero(p))
{ // main euclidean loop */
q=fulldiv(x,p);
r+=s*q;
swap(r,s);
swap(x,p);
}
ptr=x.start;
r.multerm((GF2m)1/ptr->an,0);
return r;
}
Poly2 gcd(const Poly2& f,const Poly2& g)
{
Poly2 a,b;
a=f; b=g;
term2 *ptr;
forever
{
if (b.start==NULL)
{
ptr=a.start;
a.multerm((GF2m)1/ptr->an,0);
return a;
}
a%=b;
if (a.start==NULL)
{
ptr=b.start;
b.multerm((GF2m)1/ptr->an,0);
return b;
}
b%=a;
}
}
// The extended euclidean algorithm
// The result is returned in an array of Polys, with the gcd
// in first place, then the two coefficients
void egcd(Poly2 result[], const Poly2& u, const Poly2& v)
{
Poly2 u1, u2, u3, v1, v2, v3, t1, t2, t3, zero, q;
GF2m t;
term2 *ptr;
u1 = 1;
u2 = 0;
u3 = u;
v1 = 0;
v2 = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -