#line 2 "../src/kernel/none/gcdll.c"
INLINE ulong
gcduodd(ulong x, ulong y)
{
if (!x) return y;
while (!(x&1)) x>>=1;
if (x==1) return 1;
if (x==y) return y;
else if (x>y) goto xislarger;
yislarger:
if ((x^y)&2)
y=(x>>2)+(y>>2)+1;
else
y=(y-x)>>2;
while (!(y&1)) y>>=1;
if (y==1) return 1;
if (x==y) return y;
else if (x<y) goto yislarger;
xislarger:
if ((x^y)&2)
x=(x>>2)+(y>>2)+1;
else
x=(x-y)>>2;
while (!(x&1)) x>>=1;
if (x==1) return 1;
if (x==y) return y;
else if (x>y) goto xislarger;
goto yislarger;
}
INLINE ulong
mygcduodd(ulong a, ulong b)
{
ulong c;
if (b&1)
{
if (a==1 || b==1)
c = 1;
else
c = gcduodd(a, b);
}
else
{
if (a==1)
c = 1;
else
c = gcduodd(b, a);
}
return c;
}
ulong
ugcd(ulong a,ulong b)
{
long v;
if (!b) return a;
if (!a) return b;
if (a>b) { a %= b; if (!a) return b; }
else { b %= a; if (!b) return a; }
v = vals(a|b);
return mygcduodd(a>>v, b>>v) << v;
}
long
cgcd(long a,long b) { return (long)ugcd(labs(a), labs(b)); }
static GEN
igcduu(ulong a, ulong b)
{
long v;
a %= b; if (!a) return utoipos(b);
v = vals(a|b);
return utoipos( mygcduodd(a>>v, b>>v) << v );
}
ulong
ulcm(ulong a, ulong b)
{
ulong d = ugcd(a,b);
if (!d) return 0;
return d == 1? a*b: a*(b/d);
}
long
clcm(long a,long b) { return ulcm(labs(a), labs(b)); }
ulong
xgcduu(ulong d, ulong d1, int f, ulong* v, ulong* v1, long *s)
{
ulong xv,xv1, xs, q,res;
LOCAL_HIREMAINDER;
xs = res = 0;
xv = 0UL; xv1 = 1UL;
while (d1 > 1UL)
{
d -= d1;
if (d >= d1)
{
hiremainder = 0; q = 1 + divll(d,d1); d = hiremainder;
xv += q * xv1;
}
else
xv += xv1;
if (d <= 1UL) { xs=1; break; }
d1 -= d;
if (d1 >= d)
{
hiremainder = 0; q = 1 + divll(d1,d); d1 = hiremainder;
xv1 += q * xv;
}
else
xv1 += xv;
}
if (!(f&1))
{
if (xs && d==1)
{ xv1 += d1 * xv; xs = 0; res = 1UL; }
else if (!xs && d1==1)
{ xv += d * xv1; xs = 1; res = 1UL; }
}
if (xs)
{
*s = -1; *v = xv1; *v1 = xv;
return (res ? res : (d==1 ? 1UL : d1));
}
else
{
*s = 1; *v = xv; *v1 = xv1;
return (res ? res : (d1==1 ? 1UL : d));
}
}
ulong
xxgcduu(ulong d, ulong d1, int f,
ulong* u, ulong* u1, ulong* v, ulong* v1, long *s)
{
ulong xu,xu1, xv,xv1, xs, q,res;
LOCAL_HIREMAINDER;
xs = res = 0;
xu = xv1 = 1UL;
xu1 = xv = 0UL;
while (d1 > 1UL)
{
d -= d1;
if (d >= d1)
{
hiremainder = 0; q = 1 + divll(d,d1); d = hiremainder;
xv += q * xv1;
xu += q * xu1;
}
else
{ xv += xv1; xu += xu1; }
if (d <= 1UL) { xs=1; break; }
d1 -= d;
if (d1 >= d)
{
hiremainder = 0; q = 1 + divll(d1,d); d1 = hiremainder;
xv1 += q * xv;
xu1 += q * xu;
}
else
{ xv1 += xv; xu1 += xu; }
}
if (!(f&1))
{
if (xs && d==1)
{
xv1 += d1 * xv;
xu1 += d1 * xu;
xs = 0; res = 1UL;
}
else if (!xs && d1==1)
{
xv += d * xv1;
xu += d * xu1;
xs = 1; res = 1UL;
}
}
if (xs)
{
*s = -1; *u = xu1; *u1 = xu; *v = xv1; *v1 = xv;
return (res ? res : (d==1 ? 1UL : d1));
}
else
{
*s = 1; *u = xu; *u1 = xu1; *v = xv; *v1 = xv1;
return (res ? res : (d1==1 ? 1UL : d));
}
}
ulong
rgcduu(ulong d, ulong d1, ulong vmax,
ulong* u, ulong* u1, ulong* v, ulong* v1, long *s)
{
ulong xu,xu1, xv,xv1, xs, q, res=0;
int f = 0;
LOCAL_HIREMAINDER;
if (vmax == 0) vmax = ULONG_MAX;
xs = res = 0;
xu = xv1 = 1UL;
xu1 = xv = 0UL;
while (d1 > 1UL)
{
d -= d1;
if (d >= d1)
{
hiremainder = 0; q = 1 + divll(d,d1); d = hiremainder;
xv += q * xv1;
xu += q * xu1;
}
else
{ xv += xv1; xu += xu1; }
if (xv > vmax) { f=xs=1; break; }
if (d <= 1UL) { xs=1; break; }
d1 -= d;
if (d1 >= d)
{
hiremainder = 0; q = 1 + divll(d1,d); d1 = hiremainder;
xv1 += q * xv;
xu1 += q * xu;
}
else
{ xv1 += xv; xu1 += xu; }
if (xv1 > vmax) { f=1; break; }
}
if (!(f&1))
{
if (xs && d==1)
{
xv1 += d1 * xv;
xu1 += d1 * xu;
xs = 0; res = 1UL;
}
else if (!xs && d1==1)
{
xv += d * xv1;
xu += d * xu1;
xs = 1; res = 1UL;
}
}
if (xs)
{
*s = -1; *u = xu1; *u1 = xu; *v = xv1; *v1 = xv;
return (res ? res : (d==1 ? 1UL : d1));
}
else
{
*s = 1; *u = xu; *u1 = xu1; *v = xv; *v1 = xv1;
return (res ? res : (d1==1 ? 1UL : d));
}
}
long
cbezout(long a,long b,long *uu,long *vv)
{
long s,*t;
ulong d = labs(a), d1 = labs(b);
ulong r,u,u1,v,v1;
if (!b)
{
*vv=0L;
if (!a) { *uu=1L; return 0L; }
*uu = a < 0 ? -1L : 1L;
return (long)d;
}
else if (!a || (d == d1))
{
*uu = 0L; *vv = b < 0 ? -1L : 1L;
return (long)d1;
}
else if (d == 1)
{
*uu = a; *vv = 0L;
return 1L;
}
else if (d < d1)
{
{ long _x = a; a = b; b = _x; }
r = d; d = d1; d1 = r;
t = uu; uu = vv; vv = t;
}
r = xxgcduu(d, d1, 0, &u, &u1, &v, &v1, &s);
if (s < 0)
{
*uu = a < 0 ? (long)u : -(long)u;
*vv = b < 0 ? -(long)v : (long)v;
}
else
{
*uu = a < 0 ? -(long)u : (long)u;
*vv = b < 0 ? (long)v : -(long)v;
}
return (long)r;
}
int
lgcdii(ulong* d, ulong* d1, ulong* u, ulong* u1, ulong* v, ulong* v1,
ulong vmax)
{
ulong dd,dd1,ddlo,dd1lo, sh,shc;
ulong xu,xu1, xv,xv1, q,res;
ulong tmp0,tmp1,tmp2,tmpd,tmpu,tmpv;
ulong dm1, d1m1;
long ld, ld1, lz;
int skip = 0;
LOCAL_OVERFLOW;
LOCAL_HIREMAINDER;
if (vmax == 0) vmax = ULONG_MAX;
ld = lgefint(d); ld1 = lgefint(d1); lz = ld - ld1;
if (lz > 1) return 0;
d = int_MSW(d); dm1 = *int_precW(d);
d1 = int_MSW(d1);d1m1 = *int_precW(d1);
dd1lo = 0;
sh = bfffo(*d);
if (sh)
{
shc = BITS_IN_LONG - sh;
if (lz)
{
dd1 = (*d1 >> shc);
if (!(HIGHMASK & dd1)) return 0;
if (ld1 > 3)
dd1lo = (*d1 << sh) + (d1m1 >> shc);
else
dd1lo = (*d1 << sh);
}
else
{
dd1 = (*d1 << sh);
if (!(HIGHMASK & dd1)) return 0;
if (ld1 > 3)
{
dd1 += (d1m1 >> shc);
if (ld1 > 4)
dd1lo = (d1m1 << sh) + (*int_precW(int_precW(d1)) >> shc);
else
dd1lo = (d1m1 << sh);
}
}
dd = (*d << sh) + (dm1 >> shc);
if (ld > 4)
ddlo = (dm1 << sh) + (*int_precW(int_precW(d)) >> shc);
else
ddlo = (dm1 << sh);
}
else
{
if (lz) return 0;
dd1 = *d1;
if (!(HIGHMASK & dd1)) return 0;
if(ld1 > 3) dd1lo = d1m1;
dd = *d; ddlo = dm1;
}
dd -= dd1;
if (dd < dd1)
{
xv1 = 1UL;
if (!dd)
{
*u = 0; *v = *u1 = *v1 = 1UL;
return -1;
}
}
else
{
hiremainder = 0;
xv1 = 1 + divll(dd, dd1);
dd = hiremainder;
if (dd < xv1)
{
ddlo = subll(ddlo, mulll(xv1, dd1lo));
dd = subllx(dd, hiremainder);
if (overflow)
{
xv1--;
ddlo = addll(ddlo,dd1lo);
dd = addllx(dd,dd1);
}
else
if (!dd && ddlo < xv1) return 0;
skip = 1;
}
}
res = 1;
if (xv1 > vmax)
{
*u = 0UL; *u1 = 1UL; *v = 1UL; *v1 = xv1;
return res;
}
xu = 0UL; xv = xu1 = 1UL;
if (!skip)
{
for(;;)
{
tmpd = dd1 - dd;
if (tmpd < dd)
{
tmpu = xu + xu1;
tmpv = xv + xv1;
}
else
{
hiremainder = 0;
q = 1 + divll(tmpd, dd);
tmpd = hiremainder;
tmpu = xu + q*xu1;
tmpv = xv + q*xv1;
}
tmp0 = addll(tmpv, xv1);
if ((tmpd < tmpu) || overflow ||
(dd - tmpd < tmp0))
break;
else
{
res++;
dd1 = tmpd; xu = tmpu; xv = tmpv;
if (xv > vmax) { *u = xu1; *u1 = xu; *v = xv1; *v1 = xv; return res; }
}
tmpd = dd - dd1;
if (tmpd < dd1)
{
tmpu = xu1 + xu;
tmpv = xv1 + xv;
}
else
{
hiremainder = 0;
q = 1 + divll(tmpd, dd1);
tmpd = hiremainder;
tmpu = xu1 + q*xu;
tmpv = xv1 + q*xv;
}
tmp0 = addll(tmpu, xu);
if ((tmpd < tmpv) || overflow ||
(dd1 - tmpd < tmp0))
break;
else
{
res++;
dd = tmpd; xu1 = tmpu; xv1 = tmpv;
if (xv1 > vmax) { *u = xu; *u1 = xu1; *v = xv; *v1 = xv1; return res; }
}
}
if (res&1)
{
tmp1 = mulll(ddlo, xu); tmp0 = hiremainder;
tmp1 = subll(mulll(dd1lo,xv), tmp1);
dd1 += subllx(hiremainder, tmp0);
tmp2 = mulll(ddlo, xu1); tmp0 = hiremainder;
ddlo = subll(tmp2, mulll(dd1lo,xv1));
dd += subllx(tmp0, hiremainder);
dd1lo = tmp1;
}
else
{
tmp1 = mulll(ddlo, xu1); tmp0 = hiremainder;
tmp1 = subll(tmp1, mulll(dd1lo,xv1));
dd += subllx(tmp0, hiremainder);
tmp2 = mulll(ddlo, xu); tmp0 = hiremainder;
dd1lo = subll(mulll(dd1lo,xv), tmp2);
dd1 += subllx(hiremainder, tmp0);
ddlo = tmp1;
}
}
if (res&1)
{
if (dd1 && (sh = bfffo(dd1)))
{
shc = BITS_IN_LONG - sh;
dd = (ddlo >> shc) + (dd << sh);
if (!(HIGHMASK & dd))
{
*u = xu; *u1 = xu1; *v = xv; *v1 = xv1;
return -res;
}
dd1 = (dd1lo >> shc) + (dd1 << sh);
}
else
{
*u = xu; *u1 = xu1; *v = xv; *v1 = xv1;
return res;
}
}
else
{
if (dd)
{
sh = bfffo(dd);
shc = BITS_IN_LONG - sh;
tmpd = (ddlo >> shc) + (dd << sh);
dd = (dd1lo >> shc) + (dd1 << sh);
dd1 = tmpd;
if (HIGHMASK & dd)
{
tmp0 = xu; xu = xu1; xu1 = tmp0;
tmp0 = xv; xv = xv1; xv1 = tmp0;
}
else
{
*u = xu1; *u1 = xu; *v = xv1; *v1 = xv;
return -res;
}
}
else
{
*u = xu1; *u1 = xu; *v = xv1; *v1 = xv;
return res;
}
}
for(;;)
{
tmpd = dd1 - dd;
if (tmpd < dd)
{
tmpu = xu + xu1;
tmpv = addll(xv, xv1);
tmp1 = overflow;
}
else
{
hiremainder = 0;
q = 1 + divll(tmpd, dd);
tmpd = hiremainder;
tmpu = xu + q*xu1;
tmpv = addll(xv, mulll(q,xv1));
tmp1 = overflow | hiremainder;
}
tmp0 = addll(tmpv, xv1);
if ((tmpd < tmpu) || overflow || tmp1 ||
(dd - tmpd < tmp0))
{
*u = xu; *u1 = xu1; *v = xv; *v1 = xv1;
break;
}
res++;
dd1 = tmpd; xu = tmpu; xv = tmpv;
if (xv > vmax) { *u = xu1; *u1 = xu; *v = xv1; *v1 = xv; return res; }
tmpd = dd - dd1;
if (tmpd < dd1)
{
tmpu = xu1 + xu;
tmpv = addll(xv1, xv);
tmp1 = overflow;
}
else
{
hiremainder = 0;
q = 1 + divll(tmpd, dd1);
tmpd = hiremainder;
tmpu = xu1 + q*xu;
tmpv = addll(xv1, mulll(q, xv));
tmp1 = overflow | hiremainder;
}
tmp0 = addll(tmpu, xu);
if ((tmpd < tmpv) || overflow || tmp1 ||
(dd1 - tmpd < tmp0))
{
*u = xu1; *u1 = xu; *v = xv1; *v1 = xv;
break;
}
res++;
dd = tmpd; xu1 = tmpu; xv1 = tmpv;
if (xv1 > vmax) { *u = xu; *u1 = xu1; *v = xv; *v1 = xv1; return res; }
}
return res;
}
ulong
Fl_invsafe(ulong x, ulong p)
{
long s;
ulong xv, xv1, g = xgcduu(p, x, 1, &xv, &xv1, &s);
if (g != 1UL) return 0UL;
xv = xv1 % p; if (s < 0) xv = p - xv;
return xv;
}
static ulong
lcmuu(ulong a, ulong b) { ulong d = ugcd(a,b); return (a/d) * b; }
ulong
Fl_invgen(ulong x, ulong N, ulong *pd)
{
ulong d, d0, e, v, v1;
long s;
*pd = d = xgcduu(N, x, 0, &v, &v1, &s);
if (s > 0) v = N - v;
if (d == 1) return v;
e = N / d;
d0 = u_ppo(d, e);
if (d0 == 1) return v;
e = lcmuu(e, d / d0);
return u_chinese_coprime(v, 1, e, d0, e*d0);
}
ulong
Fl_inv(ulong x, ulong p)
{
ulong xv = Fl_invsafe(x, p);
if (!xv && p!=1UL) pari_err_INV("Fl_inv", mkintmod(utoi(x), utoi(p)));
return xv;
}