Coverage Report

Created: 2025-03-09 06:52

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