Line data Source code
1 : #line 2 "../src/kernel/none/invmod.c"
2 : /* Copyright (C) 2003 The PARI group.
3 :
4 : This file is part of the PARI/GP package.
5 :
6 : PARI/GP is free software; you can redistribute it and/or modify it under the
7 : terms of the GNU General Public License as published by the Free Software
8 : Foundation; either version 2 of the License, or (at your option) any later
9 : version. It is distributed in the hope that it will be useful, but WITHOUT
10 : ANY WARRANTY WHATSOEVER.
11 :
12 : Check the License for details. You should have received a copy of it, along
13 : with the package; see the file 'COPYING'. If not, write to the Free Software
14 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
15 :
16 : /*==================================
17 : * invmod(a,b,res)
18 : *==================================
19 : * If a is invertible, return 1, and set res = a^{ -1 }
20 : * Otherwise, return 0, and set res = gcd(a,b)
21 : *
22 : * This is sufficiently different from bezout() to be implemented separately
23 : * instead of having a bunch of extra conditionals in a single function body
24 : * to meet both purposes.
25 : */
26 :
27 : #ifdef INVMOD_PARI
28 : INLINE int
29 19839995 : invmod_pari(GEN a, GEN b, GEN *res)
30 : #else
31 : int
32 15752160 : invmod(GEN a, GEN b, GEN *res)
33 : #endif
34 : {
35 : GEN v,v1,d,d1,q,r;
36 : pari_sp av, av1;
37 : long s;
38 : ulong g;
39 : ulong xu,xu1,xv,xv1; /* Lehmer stage recurrence matrix */
40 : int lhmres; /* Lehmer stage return value */
41 :
42 35592155 : if (!signe(b)) { *res=absi(a); return 0; }
43 35592155 : av = avma;
44 35592155 : if (lgefint(b) == 3) /* single-word affair */
45 : {
46 30154567 : ulong d1 = umodiu(a, uel(b,2));
47 30155285 : if (d1 == 0)
48 : {
49 349 : if (b[2] == 1L)
50 299 : { *res = gen_0; return 1; }
51 : else
52 50 : { *res = absi(b); return 0; }
53 : }
54 30154936 : g = xgcduu(uel(b,2), d1, 1, &xv, &xv1, &s);
55 30157130 : set_avma(av);
56 30156882 : if (g != 1UL) { *res = utoipos(g); return 0; }
57 30156862 : xv = xv1 % uel(b,2); if (s < 0) xv = uel(b,2) - xv;
58 30156862 : *res = utoipos(xv); return 1;
59 : }
60 :
61 5437588 : (void)new_chunk(lgefint(b));
62 5437688 : d = absi_shallow(b); d1 = modii(a,d);
63 :
64 5437684 : v=gen_0; v1=gen_1; /* general case */
65 5437684 : av1 = avma;
66 :
67 14258400 : while (lgefint(d) > 3 && signe(d1))
68 : {
69 8820716 : lhmres = lgcdii((ulong*)d, (ulong*)d1, &xu, &xu1, &xv, &xv1, ULONG_MAX);
70 8820721 : if (lhmres != 0) /* check progress */
71 : { /* apply matrix */
72 7863792 : if (lhmres == 1 || lhmres == -1)
73 : {
74 174295 : if (xv1 == 1)
75 : {
76 158115 : r = subii(d,d1); d=d1; d1=r;
77 158115 : a = subii(v,v1); v=v1; v1=a;
78 : }
79 : else
80 : {
81 16180 : r = subii(d, mului(xv1,d1)); d=d1; d1=r;
82 16180 : a = subii(v, mului(xv1,v1)); v=v1; v1=a;
83 : }
84 : }
85 : else
86 : {
87 7689497 : r = subii(muliu(d,xu), muliu(d1,xv));
88 7689494 : a = subii(muliu(v,xu), muliu(v1,xv));
89 7689496 : d1 = subii(muliu(d,xu1), muliu(d1,xv1)); d = r;
90 7689496 : v1 = subii(muliu(v,xu1), muliu(v1,xv1)); v = a;
91 7689496 : if (lhmres&1) { togglesign(d); togglesign(v); }
92 3988778 : else { togglesign(d1); togglesign(v1); }
93 : }
94 : }
95 :
96 8820720 : if (lhmres <= 0 && signe(d1))
97 : {
98 1156374 : q = dvmdii(d,d1,&r);
99 1156374 : a = subii(v,mulii(q,v1));
100 1156373 : v=v1; v1=a;
101 1156373 : d=d1; d1=r;
102 : }
103 8820719 : if (gc_needed(av,1))
104 : {
105 879 : if(DEBUGMEM>1) pari_warn(warnmem,"invmod");
106 879 : gerepileall(av1, 4, &d,&d1,&v,&v1);
107 : }
108 : } /* end while */
109 :
110 : /* Postprocessing - final sprint */
111 5437684 : if (signe(d1))
112 : {
113 : /* Assertions: lgefint(d)==lgefint(d1)==3, and
114 : * gcd(d,d1) is nonzero and fits into one word
115 : */
116 5340761 : g = xxgcduu(uel(d,2), uel(d1,2), 1, &xu, &xu1, &xv, &xv1, &s);
117 5340762 : if (g != 1UL) { set_avma(av); *res = utoipos(g); return 0; }
118 : /* (From the xgcduu() blurb:)
119 : * For finishing the multiword modinv, we now have to multiply the
120 : * returned matrix (with properly adjusted signs) onto the values
121 : * v' and v1' previously obtained from the multiword division steps.
122 : * Actually, it is sufficient to take the scalar product of [v',v1']
123 : * with [u1,-v1], and change the sign if s==1.
124 : */
125 5340644 : v = subii(muliu(v,xu1),muliu(v1,xv1));
126 5340643 : if (s > 0) setsigne(v,-signe(v));
127 5340643 : set_avma(av); *res = modii(v,b); return 1;
128 : }
129 : /* get here when the final sprint was skipped (d1 was zero already) */
130 96923 : set_avma(av);
131 96923 : if (!equalii(d,gen_1)) { *res = icopy(d); return 0; }
132 96822 : *res = modii(v,b); return 1;
133 : }
|