Coverage Report

Created: 2024-11-25 06:31

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