Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
#line 2 "../src/kernel/gmp/gcdext.c"1/* Copyright (C) 2000-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* invmod(a,b,res)17*==================================18* If a is invertible, return 1, and set res = a^{ -1 }19* Otherwise, return 0, and set res = gcd(a,b)20*/21int22invmod(GEN a, GEN b, GEN *res)23{24if (!signe(b)) { *res=absi(a); return 0; }25if (NLIMBS(b) < INVMOD_GMP_LIMIT)26return invmod_pari(a,b,res);27{ /* General case: use gcdext(a+b, b) since mpn_gcdext require S1>=S2 */28pari_sp av = avma;29GEN ca, cb, u, d;30long l, su, sa = signe(a), lb,lna;31mp_size_t lu;32GEN na;33if (!sa) { set_avma(av); *res = absi(b); return 0; }34if (signe(b) < 0) b = negi(b);35if (abscmpii(a, b) < 0)36na = sa > 0? addii(a, b): subii(a, b);37else38na = a;39/* Copy serves two purposes:40* 1) mpn_gcdext destroys its input and needs an extra limb41* 2) allows us to use icopy instead of gerepile later. */42lb = lgefint(b); lna = lgefint(na);43ca = icopy_ef(na,lna+1);44cb = icopy_ef( b,lb+1);45/* must create u first else final icopy could fail. */46u = cgeti(lna+1);47d = cgeti(lna+1);48/* na >= b */49l = mpn_gcdext(LIMBS(d), LIMBS(u), &lu, LIMBS(ca), NLIMBS(ca), LIMBS(cb), NLIMBS(cb));50d[1] = evalsigne(1)|evallgefint(l+2);51if (!is_pm1(d)) {set_avma(av); *res=icopy(d); return 0;}52su = lu?((sa ^ lu) < 0)? -1: 1: 0;53u[1] = evalsigne(su) | evallgefint(labs(lu)+2);54if (su < 0) u = addii(u, b);55set_avma(av); *res=icopy(u); return 1;56}57}5859/*==================================60* bezout(a,b,pu,pv)61*==================================62* Return g = gcd(a,b) >= 0, and assign GENs u,v through pointers pu,pv63* such that g = u*a + v*b.64* Special cases:65* a == b == 0 ==> pick u=1, v=066* a != 0 == b ==> keep v=067* a == 0 != b ==> keep u=068* |a| == |b| != 0 ==> keep u=0, set v=+-169* Assignments through pu,pv will be suppressed when the corresponding70* pointer is NULL (but the computations will happen nonetheless).71*/7273GEN74bezout(GEN a, GEN b, GEN *pu, GEN *pv)75{76long s, sa, sb;77ulong g;78ulong xu,xu1,xv,xv1; /* Lehmer stage recurrence matrix */7980s = abscmpii(a,b);81if (s < 0) { swap(a,b); pswap(pu,pv); }82/* now |a| >= |b| */8384sa = signe(a); sb = signe(b);85if (!sb)86{87if (pv) *pv = gen_0;88switch(sa)89{90case 0: if (pu) *pu = gen_0; return gen_0;91case 1: if (pu) *pu = gen_1; return icopy(a);92case -1: if (pu) *pu = gen_m1; return negi(a);93}94}95if (s == 0) /* |a| == |b| != 0 */96{97if (pu) *pu = gen_0;98if (sb > 0)99{ if (pv) *pv = gen_1; return icopy(b); }100else101{ if (pv) *pv = gen_m1; return negi(b); }102}103/* now |a| > |b| > 0 */104105if (lgefint(a) == 3) /* single-word affair */106{107g = xxgcduu((ulong)a[2], (ulong)b[2], 0, &xu, &xu1, &xv, &xv1, &s);108sa = s > 0 ? sa : -sa;109sb = s > 0 ? -sb : sb;110if (pu)111{112if (xu == 0) *pu = gen_0; /* can happen when b divides a */113else if (xu == 1) *pu = sa < 0 ? gen_m1 : gen_1;114else if (xu == 2) *pu = sa < 0 ? gen_m2 : gen_2;115else116{117*pu = cgeti(3);118(*pu)[1] = evalsigne(sa)|evallgefint(3);119(*pu)[2] = xu;120}121}122if (pv)123{124if (xv == 1) *pv = sb < 0 ? gen_m1 : gen_1;125else if (xv == 2) *pv = sb < 0 ? gen_m2 : gen_2;126else127{128*pv = cgeti(3);129(*pv)[1] = evalsigne(sb)|evallgefint(3);130(*pv)[2] = xv;131}132}133if (g == 1) return gen_1;134else if (g == 2) return gen_2;135else return utoipos(g);136}137else138{ /* general case */139pari_sp av = avma;140/*Copy serves two purposes:141* 1) mpn_gcdext destroys its input and needs an extra limb142* 2) allows us to use icopy instead of gerepile later.143* NOTE: we must put u before d else the final icopy could fail. */144GEN ca = icopy_ef(a,lgefint(a)+1);145GEN cb = icopy_ef(b,lgefint(b)+1);146GEN u = cgeti(lgefint(a)+1), v = NULL;147GEN d = cgeti(lgefint(a)+1);148long su,l;149mp_size_t lu;150l = mpn_gcdext(LIMBS(d), LIMBS(u), &lu, LIMBS(ca), NLIMBS(ca), LIMBS(cb), NLIMBS(cb));151if (lu<=0)152{153if (lu==0) su=0;154else {su=-1;lu=-lu;}155}156else157su=1;158if (sa<0) su=-su;159d[1] = evalsigne(1)|evallgefint(l+2);160u[1] = evalsigne(su)|evallgefint(lu+2);161if (pv) v=diviiexact(subii(d,mulii(u,a)),b);162set_avma(av);163if (pu) *pu=icopy(u);164if (pv) *pv=icopy(v);165return icopy(d);166}167}168169170