#line 2 "../src/kernel/none/invmod.c"
#ifdef INVMOD_PARI
INLINE int
invmod_pari(GEN a, GEN b, GEN *res)
#else
int
invmod(GEN a, GEN b, GEN *res)
#endif
{
GEN v,v1,d,d1,q,r;
pari_sp av, av1;
long s;
ulong g;
ulong xu,xu1,xv,xv1;
int lhmres;
if (!signe(b)) { *res=absi(a); return 0; }
av = avma;
if (lgefint(b) == 3)
{
ulong d1 = umodiu(a, uel(b,2));
if (d1 == 0)
{
if (b[2] == 1L)
{ *res = gen_0; return 1; }
else
{ *res = absi(b); return 0; }
}
g = xgcduu(uel(b,2), d1, 1, &xv, &xv1, &s);
avma = av;
if (g != 1UL) { *res = utoipos(g); return 0; }
xv = xv1 % uel(b,2); if (s < 0) xv = uel(b,2) - xv;
*res = utoipos(xv); return 1;
}
(void)new_chunk(lgefint(b));
d = absi_shallow(b); d1 = modii(a,d);
v=gen_0; v1=gen_1;
av1 = avma;
while (lgefint(d) > 3 && signe(d1))
{
lhmres = lgcdii((ulong*)d, (ulong*)d1, &xu, &xu1, &xv, &xv1, ULONG_MAX);
if (lhmres != 0)
{
if (lhmres == 1 || lhmres == -1)
{
if (xv1 == 1)
{
r = subii(d,d1); d=d1; d1=r;
a = subii(v,v1); v=v1; v1=a;
}
else
{
r = subii(d, mului(xv1,d1)); d=d1; d1=r;
a = subii(v, mului(xv1,v1)); v=v1; v1=a;
}
}
else
{
r = subii(muliu(d,xu), muliu(d1,xv));
a = subii(muliu(v,xu), muliu(v1,xv));
d1 = subii(muliu(d,xu1), muliu(d1,xv1)); d = r;
v1 = subii(muliu(v,xu1), muliu(v1,xv1)); v = a;
if (lhmres&1) { togglesign(d); togglesign(v); }
else { togglesign(d1); togglesign(v1); }
}
}
if (lhmres <= 0 && signe(d1))
{
q = dvmdii(d,d1,&r);
a = subii(v,mulii(q,v1));
v=v1; v1=a;
d=d1; d1=r;
}
if (gc_needed(av,1))
{
if(DEBUGMEM>1) pari_warn(warnmem,"invmod");
gerepileall(av1, 4, &d,&d1,&v,&v1);
}
}
if (signe(d1))
{
g = xxgcduu(uel(d,2), uel(d1,2), 1, &xu, &xu1, &xv, &xv1, &s);
if (g != 1UL) { avma = av; *res = utoipos(g); return 0; }
v = subii(muliu(v,xu1),muliu(v1,xv1));
if (s > 0) setsigne(v,-signe(v));
avma = av; *res = modii(v,b); return 1;
}
avma = av;
if (!equalii(d,gen_1)) { *res = icopy(d); return 0; }
*res = modii(v,b); return 1;
}