Coverage Report

Created: 2025-04-11 06:45

/src/gmp-6.2.1/mpn/gcdext_lehmer.c
Line
Count
Source (jump to first uncovered line)
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
6.41k
{
41
6.41k
  struct gcdext_ctx *ctx = (struct gcdext_ctx *) p;
42
6.41k
  mp_size_t un = ctx->un;
43
44
6.41k
  if (gp)
45
367
    {
46
367
      mp_srcptr up;
47
48
367
      ASSERT (gn > 0);
49
367
      ASSERT (gp[gn-1] > 0);
50
51
367
      MPN_COPY (ctx->gp, gp, gn);
52
367
      ctx->gn = gn;
53
54
367
      if (d < 0)
55
306
  {
56
306
    int c;
57
58
    /* Must return the smallest cofactor, +u1 or -u0 */
59
306
    MPN_CMP (c, ctx->u0, ctx->u1, un);
60
306
    ASSERT (c != 0 || (un == 1 && ctx->u0[0] == 1 && ctx->u1[0] == 1));
61
62
306
    d = c < 0;
63
306
  }
64
65
367
      up = d ? ctx->u0 : ctx->u1;
66
67
367
      MPN_NORMALIZE (up, un);
68
367
      MPN_COPY (ctx->up, up, un);
69
70
367
      *ctx->usize = d ? -un : un;
71
367
    }
72
6.04k
  else
73
6.04k
    {
74
6.04k
      mp_limb_t cy;
75
6.04k
      mp_ptr u0 = ctx->u0;
76
6.04k
      mp_ptr u1 = ctx->u1;
77
78
6.04k
      ASSERT (d >= 0);
79
80
6.04k
      if (d)
81
2.98k
  MP_PTR_SWAP (u0, u1);
82
83
6.04k
      qn -= (qp[qn-1] == 0);
84
85
      /* Update u0 += q  * u1 */
86
6.04k
      if (qn == 1)
87
3.32k
  {
88
3.32k
    mp_limb_t q = qp[0];
89
90
3.32k
    if (q == 1)
91
      /* A common case. */
92
3.05k
      cy = mpn_add_n (u0, u0, u1, un);
93
271
    else
94
271
      cy = mpn_addmul_1 (u0, u1, un, q);
95
3.32k
  }
96
2.72k
      else
97
2.72k
  {
98
2.72k
    mp_size_t u1n;
99
2.72k
    mp_ptr tp;
100
101
2.72k
    u1n = un;
102
2.72k
    MPN_NORMALIZE (u1, u1n);
103
104
2.72k
    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
2.72k
    tp = ctx->tp;
115
116
2.72k
    if (qn > u1n)
117
408
      mpn_mul (tp, qp, qn, u1, u1n);
118
2.31k
    else
119
2.31k
      mpn_mul (tp, u1, u1n, qp, qn);
120
121
2.72k
    u1n += qn;
122
2.72k
    u1n -= tp[u1n-1] == 0;
123
124
2.72k
    if (u1n >= un)
125
2.72k
      {
126
2.72k
        cy = mpn_add (u0, tp, u1n, u0, un);
127
2.72k
        un = u1n;
128
2.72k
      }
129
0
    else
130
      /* Note: Unlikely case, maybe never happens? */
131
0
      cy = mpn_add (u0, u0, un, tp, u1n);
132
133
2.72k
  }
134
6.04k
      u0[un] = cy;
135
6.04k
      ctx->un = un + (cy > 0);
136
6.04k
    }
137
6.41k
}
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
2.60k
{
149
2.60k
  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
2.60k
  struct gcdext_ctx ctx;
168
2.60k
  mp_size_t un;
169
2.60k
  mp_ptr u0;
170
2.60k
  mp_ptr u1;
171
2.60k
  mp_ptr u2;
172
173
2.60k
  MPN_ZERO (tp, 3*ualloc);
174
2.60k
  u0 = tp; tp += ualloc;
175
2.60k
  u1 = tp; tp += ualloc;
176
2.60k
  u2 = tp; tp += ualloc;
177
178
2.60k
  u1[0] = 1; un = 1;
179
180
2.60k
  ctx.gp = gp;
181
2.60k
  ctx.up = up;
182
2.60k
  ctx.usize = usize;
183
184
  /* FIXME: Handle n == 2 differently, after the loop? */
185
76.5k
  while (n >= 2)
186
74.3k
    {
187
74.3k
      struct hgcd_matrix1 M;
188
74.3k
      mp_limb_t ah, al, bh, bl;
189
74.3k
      mp_limb_t mask;
190
191
74.3k
      mask = ap[n-1] | bp[n-1];
192
74.3k
      ASSERT (mask > 0);
193
194
74.3k
      if (mask & GMP_NUMB_HIGHBIT)
195
1.53k
  {
196
1.53k
    ah = ap[n-1]; al = ap[n-2];
197
1.53k
    bh = bp[n-1]; bl = bp[n-2];
198
1.53k
  }
199
72.8k
      else if (n == 2)
200
1.66k
  {
201
    /* We use the full inputs without truncation, so we can
202
       safely shift left. */
203
1.66k
    int shift;
204
205
1.66k
    count_leading_zeros (shift, mask);
206
1.66k
    ah = MPN_EXTRACT_NUMB (shift, ap[1], ap[0]);
207
1.66k
    al = ap[0] << shift;
208
1.66k
    bh = MPN_EXTRACT_NUMB (shift, bp[1], bp[0]);
209
1.66k
    bl = bp[0] << shift;
210
1.66k
  }
211
71.1k
      else
212
71.1k
  {
213
71.1k
    int shift;
214
215
71.1k
    count_leading_zeros (shift, mask);
216
71.1k
    ah = MPN_EXTRACT_NUMB (shift, ap[n-1], ap[n-2]);
217
71.1k
    al = MPN_EXTRACT_NUMB (shift, ap[n-2], ap[n-3]);
218
71.1k
    bh = MPN_EXTRACT_NUMB (shift, bp[n-1], bp[n-2]);
219
71.1k
    bl = MPN_EXTRACT_NUMB (shift, bp[n-2], bp[n-3]);
220
71.1k
  }
221
222
      /* Try an mpn_nhgcd2 step */
223
74.3k
      if (mpn_hgcd2 (ah, al, bh, bl, &M))
224
70.9k
  {
225
70.9k
    n = mpn_matrix22_mul1_inverse_vector (&M, tp, ap, bp, n);
226
70.9k
    MP_PTR_SWAP (ap, tp);
227
70.9k
    un = mpn_hgcd_mul_matrix1_vector(&M, u2, u0, u1, un);
228
70.9k
    MP_PTR_SWAP (u0, u2);
229
70.9k
  }
230
3.36k
      else
231
3.36k
  {
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
3.36k
    ctx.u0 = u0;
236
3.36k
    ctx.u1 = u1;
237
3.36k
    ctx.tp = u2;
238
3.36k
    ctx.un = un;
239
240
    /* Temporary storage n for the quotient and ualloc for the
241
       new cofactor. */
242
3.36k
    n = mpn_gcd_subdiv_step (ap, bp, n, 0, mpn_gcdext_hook, &ctx, tp);
243
3.36k
    if (n == 0)
244
367
      return ctx.gn;
245
246
2.99k
    un = ctx.un;
247
2.99k
  }
248
74.3k
    }
249
2.23k
  ASSERT_ALWAYS (ap[0] > 0);
250
2.23k
  ASSERT_ALWAYS (bp[0] > 0);
251
252
2.23k
  if (ap[0] == bp[0])
253
201
    {
254
201
      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
201
      gp[0] = ap[0];
262
263
201
      MPN_CMP (c, u0, u1, un);
264
201
      ASSERT (c != 0 || (un == 1 && u0[0] == 1 && u1[0] == 1));
265
201
      if (c < 0)
266
88
  {
267
88
    MPN_NORMALIZE (u0, un);
268
88
    MPN_COPY (up, u0, un);
269
88
    *usize = -un;
270
88
  }
271
113
      else
272
113
  {
273
113
    MPN_NORMALIZE_NOT_ZERO (u1, un);
274
113
    MPN_COPY (up, u1, un);
275
113
    *usize = un;
276
113
  }
277
201
      return 1;
278
201
    }
279
2.03k
  else
280
2.03k
    {
281
2.03k
      mp_limb_t uh, vh;
282
2.03k
      mp_limb_signed_t u;
283
2.03k
      mp_limb_signed_t v;
284
2.03k
      int negate;
285
286
2.03k
      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
2.03k
      if (u == 0)
292
8
  {
293
8
    ASSERT (v == 1);
294
8
    MPN_NORMALIZE (u0, un);
295
8
    MPN_COPY (up, u0, un);
296
8
    *usize = -un;
297
8
    return 1;
298
8
  }
299
2.02k
      else if (v == 0)
300
61
  {
301
61
    ASSERT (u == 1);
302
61
    MPN_NORMALIZE (u1, un);
303
61
    MPN_COPY (up, u1, un);
304
61
    *usize = un;
305
61
    return 1;
306
61
  }
307
1.96k
      else if (u > 0)
308
974
  {
309
974
    negate = 0;
310
974
    ASSERT (v < 0);
311
974
    v = -v;
312
974
  }
313
989
      else
314
989
  {
315
989
    negate = 1;
316
989
    ASSERT (v > 0);
317
989
    u = -u;
318
989
  }
319
320
1.96k
      uh = mpn_mul_1 (up, u1, un, u);
321
1.96k
      vh = mpn_addmul_1 (up, u0, un, v);
322
323
1.96k
      if ( (uh | vh) > 0)
324
515
  {
325
515
    uh += vh;
326
515
    up[un++] = uh;
327
515
    if (uh < vh)
328
0
      up[un++] = 1;
329
515
  }
330
331
1.96k
      MPN_NORMALIZE_NOT_ZERO (up, un);
332
333
1.96k
      *usize = negate ? -un : un;
334
1.96k
      return 1;
335
1.96k
    }
336
2.23k
}