Coverage Report

Created: 2026-02-14 06:49

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