1 /* mpn_gcdext -- Extended Greatest Common Divisor.
3 Copyright 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 Free Software
6 This file is part of the GNU MP Library.
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.
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.
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/. */
25 /* Temporary storage: 3*(n+1) for u. n+1 for the matrix-vector
26 multiplications (if hgcd2 succeeds). If hgcd fails, n+1 limbs are
27 needed for the division, with most n for the quotient, and n+1 for
28 the product q u0. In all, 4n + 3. */
31 mpn_gcdext_lehmer_n (mp_ptr gp, mp_ptr up, mp_size_t *usize,
32 mp_ptr ap, mp_ptr bp, mp_size_t n,
35 mp_size_t ualloc = n + 1;
37 /* Keeps track of the second row of the reduction matrix
39 * M = (v0, v1 ; u0, u1)
41 * which correspond to the first column of the inverse
43 * M^{-1} = (u1, -v1; -u0, v0)
51 MPN_ZERO (tp, 3*ualloc);
52 u0 = tp; tp += ualloc;
53 u1 = tp; tp += ualloc;
54 u2 = tp; tp += ualloc;
58 /* FIXME: Handle n == 2 differently, after the loop? */
61 struct hgcd_matrix1 M;
62 mp_limb_t ah, al, bh, bl;
65 mask = ap[n-1] | bp[n-1];
68 if (mask & GMP_NUMB_HIGHBIT)
70 ah = ap[n-1]; al = ap[n-2];
71 bh = bp[n-1]; bl = bp[n-2];
75 /* We use the full inputs without truncation, so we can
79 count_leading_zeros (shift, mask);
80 ah = MPN_EXTRACT_NUMB (shift, ap[1], ap[0]);
82 bh = MPN_EXTRACT_NUMB (shift, bp[1], bp[0]);
89 count_leading_zeros (shift, mask);
90 ah = MPN_EXTRACT_NUMB (shift, ap[n-1], ap[n-2]);
91 al = MPN_EXTRACT_NUMB (shift, ap[n-2], ap[n-3]);
92 bh = MPN_EXTRACT_NUMB (shift, bp[n-1], bp[n-2]);
93 bl = MPN_EXTRACT_NUMB (shift, bp[n-2], bp[n-3]);
96 /* Try an mpn_nhgcd2 step */
97 if (mpn_hgcd2 (ah, al, bh, bl, &M))
99 n = mpn_hgcd_mul_matrix1_inverse_vector (&M, tp, ap, bp, n);
100 MP_PTR_SWAP (ap, tp);
101 un = mpn_hgcd_mul_matrix1_vector(&M, u2, u0, u1, un);
102 MP_PTR_SWAP (u0, u2);
106 /* mpn_hgcd2 has failed. Then either one of a or b is very
107 small, or the difference is very small. Perform one
108 subtraction followed by one division. */
110 mp_size_t updated_un = un;
112 /* Temporary storage n for the quotient and ualloc for the
114 n = mpn_gcdext_subdiv_step (gp, &gn, up, usize, ap, bp, n,
115 u0, u1, &updated_un, tp, u2);
122 ASSERT_ALWAYS (ap[0] > 0);
123 ASSERT_ALWAYS (bp[0] > 0);
129 /* Which cofactor to return now? Candidates are +u1 and -u0,
130 depending on which of a and b was most recently reduced,
131 which we don't keep track of. So compare and get the smallest
136 MPN_CMP (c, u0, u1, un);
137 ASSERT (c != 0 || (un == 1 && u0[0] == 1 && u1[0] == 1));
140 MPN_NORMALIZE (u0, un);
141 MPN_COPY (up, u0, un);
146 MPN_NORMALIZE_NOT_ZERO (u1, un);
147 MPN_COPY (up, u1, un);
159 gp[0] = mpn_gcdext_1 (&u, &v, ap[0], bp[0]);
161 /* Set up = u u1 - v u0. Keep track of size, un grows by one or
167 MPN_NORMALIZE (u0, un);
168 MPN_COPY (up, u0, un);
175 MPN_NORMALIZE (u1, un);
176 MPN_COPY (up, u1, un);
193 uh = mpn_mul_1 (up, u1, un, u);
194 vh = mpn_addmul_1 (up, u0, un, v);
204 MPN_NORMALIZE_NOT_ZERO (up, un);
206 *usize = negate ? -un : un;