Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
#line 2 "../src/kernel/none/gcdext.c"1/* Copyright (C) 2003 The PARI group.23This file is part of the PARI/GP package.45PARI/GP is free software; you can redistribute it and/or modify it under the6terms of the GNU General Public License as published by the Free Software7Foundation; either version 2 of the License, or (at your option) any later8version. It is distributed in the hope that it will be useful, but WITHOUT9ANY WARRANTY WHATSOEVER.1011Check the License for details. You should have received a copy of it, along12with the package; see the file 'COPYING'. If not, write to the Free Software13Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */1415/*==================================16* bezout(a,b,pu,pv)17*==================================18* Return g = gcd(a,b) >= 0, and assign GENs u,v through pointers pu,pv19* such that g = u*a + v*b.20* Special cases:21* a == b == 0 ==> pick u=1, v=022* a != 0 == b ==> keep v=023* a == 0 != b ==> keep u=024* |a| == |b| != 0 ==> keep u=0, set v=+-125* Assignments through pu,pv will be suppressed when the corresponding26* pointer is NULL (but the computations will happen nonetheless).27*/2829static GEN30bezout_lehmer(GEN a, GEN b, GEN *pu, GEN *pv)31{32GEN t,u,u1,v,v1,d,d1,q,r;33GEN *pt;34pari_sp av, av1;35long s, sa, sb;36ulong g;37ulong xu,xu1,xv,xv1; /* Lehmer stage recurrence matrix */38int lhmres; /* Lehmer stage return value */3940s = abscmpii(a,b);41if (s < 0)42{43t=b; b=a; a=t;44pt=pu; pu=pv; pv=pt;45}46/* now |a| >= |b| */4748sa = signe(a); sb = signe(b);49if (!sb)50{51if (pv) *pv = gen_0;52switch(sa)53{54case 0: if (pu) *pu = gen_0; return gen_0;55case 1: if (pu) *pu = gen_1; return icopy(a);56case -1: if (pu) *pu = gen_m1; return(negi(a));57}58}59if (s == 0) /* |a| == |b| != 0 */60{61if (pu) *pu = gen_0;62if (sb > 0)63{ if (pv) *pv = gen_1; return icopy(b); }64else65{ if (pv) *pv = gen_m1; return(negi(b)); }66}67/* now |a| > |b| > 0 */6869if (lgefint(a) == 3) /* single-word affair */70{71g = xxgcduu(uel(a,2), uel(b,2), 0, &xu, &xu1, &xv, &xv1, &s);72sa = s > 0 ? sa : -sa;73sb = s > 0 ? -sb : sb;74if (pu)75{76if (xu == 0) *pu = gen_0; /* can happen when b divides a */77else if (xu == 1) *pu = sa < 0 ? gen_m1 : gen_1;78else if (xu == 2) *pu = sa < 0 ? gen_m2 : gen_2;79else80{81*pu = cgeti(3);82(*pu)[1] = evalsigne(sa)|evallgefint(3);83(*pu)[2] = xu;84}85}86if (pv)87{88if (xv == 1) *pv = sb < 0 ? gen_m1 : gen_1;89else if (xv == 2) *pv = sb < 0 ? gen_m2 : gen_2;90else91{92*pv = cgeti(3);93(*pv)[1] = evalsigne(sb)|evallgefint(3);94(*pv)[2] = xv;95}96}97if (g == 1) return gen_1;98else if (g == 2) return gen_2;99else return utoipos(g);100}101102/* general case */103av = avma;104(void)new_chunk(lgefint(b) + (lgefint(a)<<1)); /* room for u,v,gcd */105/* if a is significantly larger than b, calling lgcdii() is not the best106* way to start -- reduce a mod b first107*/108if (lgefint(a) > lgefint(b))109{110d = absi_shallow(b);111q = dvmdii(absi_shallow(a), d, &d1);112if (!signe(d1)) /* a == qb */113{114set_avma(av);115if (pu) *pu = gen_0;116if (pv) *pv = sb < 0 ? gen_m1 : gen_1;117return icopy(d);118}119else120{121u = gen_0;122u1 = v = gen_1;123v1 = negi(q);124}125/* if this results in lgefint(d) == 3, will fall past main loop */126}127else128{129d = absi_shallow(a);130d1 = absi_shallow(b);131u = v1 = gen_1; u1 = v = gen_0;132}133av1 = avma;134135/* main loop is almost identical to that of invmod() */136while (lgefint(d) > 3 && signe(d1))137{138lhmres = lgcdii((ulong *)d, (ulong *)d1, &xu, &xu1, &xv, &xv1, ULONG_MAX);139if (lhmres != 0) /* check progress */140{ /* apply matrix */141if ((lhmres == 1) || (lhmres == -1))142{143if (xv1 == 1)144{145r = subii(d,d1); d=d1; d1=r;146a = subii(u,u1); u=u1; u1=a;147a = subii(v,v1); v=v1; v1=a;148}149else150{151r = subii(d, mului(xv1,d1)); d=d1; d1=r;152a = subii(u, mului(xv1,u1)); u=u1; u1=a;153a = subii(v, mului(xv1,v1)); v=v1; v1=a;154}155}156else157{158r = subii(muliu(d,xu), muliu(d1,xv));159d1 = subii(muliu(d,xu1), muliu(d1,xv1)); d = r;160a = subii(muliu(u,xu), muliu(u1,xv));161u1 = subii(muliu(u,xu1), muliu(u1,xv1)); u = a;162a = subii(muliu(v,xu), muliu(v1,xv));163v1 = subii(muliu(v,xu1), muliu(v1,xv1)); v = a;164if (lhmres&1) { togglesign(d); togglesign(u); togglesign(v); }165else { togglesign(d1); togglesign(u1); togglesign(v1); }166}167}168if (lhmres <= 0 && signe(d1))169{170q = dvmdii(d,d1,&r);171a = subii(u,mulii(q,u1));172u=u1; u1=a;173a = subii(v,mulii(q,v1));174v=v1; v1=a;175d=d1; d1=r;176}177if (gc_needed(av,1))178{179if(DEBUGMEM>1) pari_warn(warnmem,"bezout");180gerepileall(av1,6, &d,&d1,&u,&u1,&v,&v1);181}182} /* end while */183184/* Postprocessing - final sprint */185if (signe(d1))186{187/* Assertions: lgefint(d)==lgefint(d1)==3, and188* gcd(d,d1) is nonzero and fits into one word189*/190g = xxgcduu(uel(d,2), uel(d1,2), 0, &xu, &xu1, &xv, &xv1, &s);191u = subii(muliu(u,xu), muliu(u1, xv));192v = subii(muliu(v,xu), muliu(v1, xv));193if (s < 0) { sa = -sa; sb = -sb; }194set_avma(av);195if (pu) *pu = sa < 0 ? negi(u) : icopy(u);196if (pv) *pv = sb < 0 ? negi(v) : icopy(v);197if (g == 1) return gen_1;198else if (g == 2) return gen_2;199else return utoipos(g);200}201/* get here when the final sprint was skipped (d1 was zero already).202* Now the matrix is final, and d contains the gcd.203*/204set_avma(av);205if (pu) *pu = sa < 0 ? negi(u) : icopy(u);206if (pv) *pv = sb < 0 ? negi(v) : icopy(v);207return icopy(d);208}209210static GEN211addmulmul(GEN u, GEN v, GEN x, GEN y)212{ return addii(mulii(u, x),mulii(v, y)); }213214static GEN215bezout_halfgcd(GEN x, GEN y, GEN *ptu, GEN *ptv)216{217pari_sp av=avma;218GEN u, v, R = matid(2);219while (lgefint(y)-2 >= EXTGCD_HALFGCD_LIMIT)220{221GEN M = HGCD0(x,y);222R = ZM2_mul(R, gel(M, 1));223x = gel(M,2); y = gel(M,3);224if (signe(y) && expi(y)<magic_threshold(x))225{226GEN r, q = dvmdii(x, y, &r);227x = y; y = r;228R = mulq(R, q);229}230if (gc_needed(av, 1))231gerepileall(av,3,&x,&y,&R);232}233y = bezout_lehmer(x,y,&u,&v);234R = ZM_inv2(R);235if (ptu) *ptu = addmulmul(u,v,gcoeff(R,1,1),gcoeff(R,2,1));236if (ptv) *ptv = addmulmul(u,v,gcoeff(R,1,2),gcoeff(R,2,2));237return y;238}239240GEN241bezout(GEN x, GEN y, GEN *ptu, GEN *ptv)242{243pari_sp ltop=avma;244GEN d;245if (lgefint(y)-2 >= EXTGCD_HALFGCD_LIMIT)246d = bezout_halfgcd(x, y, ptu, ptv);247else248d = bezout_lehmer(x, y, ptu, ptv);249if (ptv) gerepileall(ltop,ptu?3:2,&d,ptv,ptu);250else gerepileall(ltop,ptu?2:1,&d,ptu);251return d;252}253254255