gcdext_lehmer.c revision 1.1.1.1.8.1 1 /* mpn_gcdext -- Extended Greatest Common Divisor.
2
3 Copyright 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2012 Free
4 Software Foundation, Inc.
5
6 This file is part of the GNU MP Library.
7
8 The GNU MP Library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12
13 The GNU MP Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16 License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
20
21 #include "gmp.h"
22 #include "gmp-impl.h"
23 #include "longlong.h"
24
25 /* Here, d is the index of the cofactor to update. FIXME: Could use qn
26 = 0 for the common case q = 1. */
27 void
28 mpn_gcdext_hook (void *p, mp_srcptr gp, mp_size_t gn,
29 mp_srcptr qp, mp_size_t qn, int d)
30 {
31 struct gcdext_ctx *ctx = (struct gcdext_ctx *) p;
32 mp_size_t un = ctx->un;
33
34 if (gp)
35 {
36 mp_srcptr up;
37
38 ASSERT (gn > 0);
39 ASSERT (gp[gn-1] > 0);
40
41 MPN_COPY (ctx->gp, gp, gn);
42 ctx->gn = gn;
43
44 if (d < 0)
45 {
46 int c;
47
48 /* Must return the smallest cofactor, +u1 or -u0 */
49 MPN_CMP (c, ctx->u0, ctx->u1, un);
50 ASSERT (c != 0 || (un == 1 && ctx->u0[0] == 1 && ctx->u1[0] == 1));
51
52 d = c < 0;
53 }
54
55 up = d ? ctx->u0 : ctx->u1;
56
57 MPN_NORMALIZE (up, un);
58 MPN_COPY (ctx->up, up, un);
59
60 *ctx->usize = d ? -un : un;
61 }
62 else
63 {
64 mp_limb_t cy;
65 mp_ptr u0 = ctx->u0;
66 mp_ptr u1 = ctx->u1;
67
68 ASSERT (d >= 0);
69
70 if (d)
71 MP_PTR_SWAP (u0, u1);
72
73 qn -= (qp[qn-1] == 0);
74
75 /* Update u0 += q * u1 */
76 if (qn == 1)
77 {
78 mp_limb_t q = qp[0];
79
80 if (q == 1)
81 /* A common case. */
82 cy = mpn_add_n (u0, u0, u1, un);
83 else
84 cy = mpn_addmul_1 (u0, u1, un, q);
85 }
86 else
87 {
88 mp_size_t u1n;
89 mp_ptr tp;
90
91 u1n = un;
92 MPN_NORMALIZE (u1, u1n);
93
94 if (u1n == 0)
95 return;
96
97 /* Should always have u1n == un here, and u1 >= u0. The
98 reason is that we alternate adding u0 to u1 and u1 to u0
99 (corresponding to subtractions a - b and b - a), and we
100 can get a large quotient only just after a switch, which
101 means that we'll add (a multiple of) the larger u to the
102 smaller. */
103
104 tp = ctx->tp;
105
106 if (qn > u1n)
107 mpn_mul (tp, qp, qn, u1, u1n);
108 else
109 mpn_mul (tp, u1, u1n, qp, qn);
110
111 u1n += qn;
112 u1n -= tp[u1n-1] == 0;
113
114 if (u1n >= un)
115 {
116 cy = mpn_add (u0, tp, u1n, u0, un);
117 un = u1n;
118 }
119 else
120 /* Note: Unlikely case, maybe never happens? */
121 cy = mpn_add (u0, u0, un, tp, u1n);
122
123 }
124 u0[un] = cy;
125 ctx->un = un + (cy > 0);
126 }
127 }
128
129 /* Temporary storage: 3*(n+1) for u. If hgcd2 succeeds, we need n for
130 the matrix-vector multiplication adjusting a, b. If hgcd fails, we
131 need at most n for the quotient and n+1 for the u update (reusing
132 the extra u). In all, 4n + 3. */
133
134 mp_size_t
135 mpn_gcdext_lehmer_n (mp_ptr gp, mp_ptr up, mp_size_t *usize,
136 mp_ptr ap, mp_ptr bp, mp_size_t n,
137 mp_ptr tp)
138 {
139 mp_size_t ualloc = n + 1;
140
141 /* Keeps track of the second row of the reduction matrix
142 *
143 * M = (v0, v1 ; u0, u1)
144 *
145 * which correspond to the first column of the inverse
146 *
147 * M^{-1} = (u1, -v1; -u0, v0)
148 *
149 * This implies that
150 *
151 * a = u1 A (mod B)
152 * b = -u0 A (mod B)
153 *
154 * where A, B denotes the input values.
155 */
156
157 struct gcdext_ctx ctx;
158 mp_size_t un;
159 mp_ptr u0;
160 mp_ptr u1;
161 mp_ptr u2;
162
163 MPN_ZERO (tp, 3*ualloc);
164 u0 = tp; tp += ualloc;
165 u1 = tp; tp += ualloc;
166 u2 = tp; tp += ualloc;
167
168 u1[0] = 1; un = 1;
169
170 ctx.gp = gp;
171 ctx.up = up;
172 ctx.usize = usize;
173
174 /* FIXME: Handle n == 2 differently, after the loop? */
175 while (n >= 2)
176 {
177 struct hgcd_matrix1 M;
178 mp_limb_t ah, al, bh, bl;
179 mp_limb_t mask;
180
181 mask = ap[n-1] | bp[n-1];
182 ASSERT (mask > 0);
183
184 if (mask & GMP_NUMB_HIGHBIT)
185 {
186 ah = ap[n-1]; al = ap[n-2];
187 bh = bp[n-1]; bl = bp[n-2];
188 }
189 else if (n == 2)
190 {
191 /* We use the full inputs without truncation, so we can
192 safely shift left. */
193 int shift;
194
195 count_leading_zeros (shift, mask);
196 ah = MPN_EXTRACT_NUMB (shift, ap[1], ap[0]);
197 al = ap[0] << shift;
198 bh = MPN_EXTRACT_NUMB (shift, bp[1], bp[0]);
199 bl = bp[0] << shift;
200 }
201 else
202 {
203 int shift;
204
205 count_leading_zeros (shift, mask);
206 ah = MPN_EXTRACT_NUMB (shift, ap[n-1], ap[n-2]);
207 al = MPN_EXTRACT_NUMB (shift, ap[n-2], ap[n-3]);
208 bh = MPN_EXTRACT_NUMB (shift, bp[n-1], bp[n-2]);
209 bl = MPN_EXTRACT_NUMB (shift, bp[n-2], bp[n-3]);
210 }
211
212 /* Try an mpn_nhgcd2 step */
213 if (mpn_hgcd2 (ah, al, bh, bl, &M))
214 {
215 n = mpn_matrix22_mul1_inverse_vector (&M, tp, ap, bp, n);
216 MP_PTR_SWAP (ap, tp);
217 un = mpn_hgcd_mul_matrix1_vector(&M, u2, u0, u1, un);
218 MP_PTR_SWAP (u0, u2);
219 }
220 else
221 {
222 /* mpn_hgcd2 has failed. Then either one of a or b is very
223 small, or the difference is very small. Perform one
224 subtraction followed by one division. */
225 ctx.u0 = u0;
226 ctx.u1 = u1;
227 ctx.tp = u2;
228 ctx.un = un;
229
230 /* Temporary storage n for the quotient and ualloc for the
231 new cofactor. */
232 n = mpn_gcd_subdiv_step (ap, bp, n, 0, mpn_gcdext_hook, &ctx, tp);
233 if (n == 0)
234 return ctx.gn;
235
236 un = ctx.un;
237 }
238 }
239 ASSERT_ALWAYS (ap[0] > 0);
240 ASSERT_ALWAYS (bp[0] > 0);
241
242 if (ap[0] == bp[0])
243 {
244 int c;
245
246 /* Which cofactor to return now? Candidates are +u1 and -u0,
247 depending on which of a and b was most recently reduced,
248 which we don't keep track of. So compare and get the smallest
249 one. */
250
251 gp[0] = ap[0];
252
253 MPN_CMP (c, u0, u1, un);
254 ASSERT (c != 0 || (un == 1 && u0[0] == 1 && u1[0] == 1));
255 if (c < 0)
256 {
257 MPN_NORMALIZE (u0, un);
258 MPN_COPY (up, u0, un);
259 *usize = -un;
260 }
261 else
262 {
263 MPN_NORMALIZE_NOT_ZERO (u1, un);
264 MPN_COPY (up, u1, un);
265 *usize = un;
266 }
267 return 1;
268 }
269 else
270 {
271 mp_limb_t uh, vh;
272 mp_limb_signed_t u;
273 mp_limb_signed_t v;
274 int negate;
275
276 gp[0] = mpn_gcdext_1 (&u, &v, ap[0], bp[0]);
277
278 /* Set up = u u1 - v u0. Keep track of size, un grows by one or
279 two limbs. */
280
281 if (u == 0)
282 {
283 ASSERT (v == 1);
284 MPN_NORMALIZE (u0, un);
285 MPN_COPY (up, u0, un);
286 *usize = -un;
287 return 1;
288 }
289 else if (v == 0)
290 {
291 ASSERT (u == 1);
292 MPN_NORMALIZE (u1, un);
293 MPN_COPY (up, u1, un);
294 *usize = un;
295 return 1;
296 }
297 else if (u > 0)
298 {
299 negate = 0;
300 ASSERT (v < 0);
301 v = -v;
302 }
303 else
304 {
305 negate = 1;
306 ASSERT (v > 0);
307 u = -u;
308 }
309
310 uh = mpn_mul_1 (up, u1, un, u);
311 vh = mpn_addmul_1 (up, u0, un, v);
312
313 if ( (uh | vh) > 0)
314 {
315 uh += vh;
316 up[un++] = uh;
317 if (uh < vh)
318 up[un++] = 1;
319 }
320
321 MPN_NORMALIZE_NOT_ZERO (up, un);
322
323 *usize = negate ? -un : un;
324 return 1;
325 }
326 }
327