Coverage Report

Created: 2026-09-28 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gmp/mpn/hgcd2.c
Line
Count
Source
1
/* hgcd2.c
2
3
   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
4
   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
5
   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
6
7
Copyright 1996, 1998, 2000-2004, 2008, 2012, 2019 Free Software Foundation,
8
Inc.
9
10
This file is part of the GNU MP Library.
11
12
The GNU MP Library is free software; you can redistribute it and/or modify
13
it under the terms of either:
14
15
  * the GNU Lesser General Public License as published by the Free
16
    Software Foundation; either version 3 of the License, or (at your
17
    option) any later version.
18
19
or
20
21
  * the GNU General Public License as published by the Free Software
22
    Foundation; either version 2 of the License, or (at your option) any
23
    later version.
24
25
or both in parallel, as here.
26
27
The GNU MP Library is distributed in the hope that it will be useful, but
28
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
29
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
30
for more details.
31
32
You should have received copies of the GNU General Public License and the
33
GNU Lesser General Public License along with the GNU MP Library.  If not,
34
see https://www.gnu.org/licenses/.  */
35
36
#include "gmp-impl.h"
37
#include "longlong.h"
38
39
#include "mpn/generic/hgcd2-div.h"
40
41
#if GMP_NAIL_BITS != 0
42
#error Nails not implemented
43
#endif
44
45
/* Reduces a,b until |a-b| (almost) fits in one limb + 1 bit. Constructs
46
   matrix M. Returns 1 if we make progress, i.e. can perform at least
47
   one subtraction. Otherwise returns zero. */
48
49
/* FIXME: Possible optimizations:
50
51
   The div2 function starts with checking the most significant bit of
52
   the numerator. We can maintained normalized operands here, call
53
   hgcd with normalized operands only, which should make the code
54
   simpler and possibly faster.
55
56
   Experiment with table lookups on the most significant bits.
57
58
   This function is also a candidate for assembler implementation.
59
*/
60
int
61
mpn_hgcd2 (mp_limb_t ah, mp_limb_t al, mp_limb_t bh, mp_limb_t bl,
62
     struct hgcd_matrix1 *M)
63
375k
{
64
375k
  mp_limb_t u00, u01, u10, u11;
65
66
375k
  if (ah < 2 || bh < 2)
67
1.59k
    return 0;
68
69
373k
  if (ah > bh || (ah == bh && al > bl))
70
200k
    {
71
200k
      sub_ddmmss (ah, al, ah, al, bh, bl);
72
200k
      if (ah < 2)
73
3.16k
  return 0;
74
75
196k
      u00 = u01 = u11 = 1;
76
196k
      u10 = 0;
77
196k
    }
78
173k
  else
79
173k
    {
80
173k
      sub_ddmmss (bh, bl, bh, bl, ah, al);
81
173k
      if (bh < 2)
82
3.86k
  return 0;
83
84
169k
      u00 = u10 = u11 = 1;
85
169k
      u01 = 0;
86
169k
    }
87
88
366k
  if (ah < bh)
89
200k
    goto subtract_a;
90
91
166k
  for (;;)
92
3.46M
    {
93
3.46M
      ASSERT (ah >= bh);
94
3.46M
      if (ah == bh)
95
733
  goto done;
96
97
3.46M
      if (ah < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2)))
98
195k
  {
99
195k
    ah = (ah << (GMP_LIMB_BITS / 2) ) + (al >> (GMP_LIMB_BITS / 2));
100
195k
    bh = (bh << (GMP_LIMB_BITS / 2) ) + (bl >> (GMP_LIMB_BITS / 2));
101
102
195k
    break;
103
195k
  }
104
105
      /* Subtract a -= q b, and multiply M from the right by (1 q ; 0
106
   1), affecting the second column of M. */
107
3.26M
      ASSERT (ah > bh);
108
3.26M
      sub_ddmmss (ah, al, ah, al, bh, bl);
109
110
3.26M
      if (ah < 2)
111
743
  goto done;
112
113
3.26M
      if (ah <= bh)
114
1.28M
  {
115
    /* Use q = 1 */
116
1.28M
    u01 += u00;
117
1.28M
    u11 += u10;
118
1.28M
  }
119
1.97M
      else
120
1.97M
  {
121
1.97M
    mp_limb_t r[2];
122
1.97M
    mp_limb_t q = div2 (r, ah, al, bh, bl);
123
1.97M
    al = r[0]; ah = r[1];
124
1.97M
    if (ah < 2)
125
1.69k
      {
126
        /* A is too small, but q is correct. */
127
1.69k
        u01 += q * u00;
128
1.69k
        u11 += q * u10;
129
1.69k
        goto done;
130
1.69k
      }
131
1.97M
    q++;
132
1.97M
    u01 += q * u00;
133
1.97M
    u11 += q * u10;
134
1.97M
  }
135
3.46M
    subtract_a:
136
3.46M
      ASSERT (bh >= ah);
137
3.46M
      if (ah == bh)
138
708
  goto done;
139
140
3.46M
      if (bh < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2)))
141
164k
  {
142
164k
    ah = (ah << (GMP_LIMB_BITS / 2) ) + (al >> (GMP_LIMB_BITS / 2));
143
164k
    bh = (bh << (GMP_LIMB_BITS / 2) ) + (bl >> (GMP_LIMB_BITS / 2));
144
145
164k
    goto subtract_a1;
146
164k
  }
147
148
      /* Subtract b -= q a, and multiply M from the right by (1 0 ; q
149
   1), affecting the first column of M. */
150
3.29M
      sub_ddmmss (bh, bl, bh, bl, ah, al);
151
152
3.29M
      if (bh < 2)
153
693
  goto done;
154
155
3.29M
      if (bh <= ah)
156
1.31M
  {
157
    /* Use q = 1 */
158
1.31M
    u00 += u01;
159
1.31M
    u10 += u11;
160
1.31M
  }
161
1.98M
      else
162
1.98M
  {
163
1.98M
    mp_limb_t r[2];
164
1.98M
    mp_limb_t q = div2 (r, bh, bl, ah, al);
165
1.98M
    bl = r[0]; bh = r[1];
166
1.98M
    if (bh < 2)
167
1.59k
      {
168
        /* B is too small, but q is correct. */
169
1.59k
        u00 += q * u01;
170
1.59k
        u10 += q * u11;
171
1.59k
        goto done;
172
1.59k
      }
173
1.98M
    q++;
174
1.98M
    u00 += q * u01;
175
1.98M
    u10 += q * u11;
176
1.98M
  }
177
3.29M
    }
178
179
  /* NOTE: Since we discard the least significant half limb, we don't get a
180
     truly maximal M (corresponding to |a - b| < 2^{GMP_LIMB_BITS +1}). */
181
  /* Single precision loop */
182
195k
  for (;;)
183
3.09M
    {
184
3.09M
      ASSERT (ah >= bh);
185
186
3.09M
      ah -= bh;
187
3.09M
      if (ah < (CNST_LIMB (1) << (GMP_LIMB_BITS / 2 + 1)))
188
98.8k
  break;
189
190
2.99M
      if (ah <= bh)
191
1.31M
  {
192
    /* Use q = 1 */
193
1.31M
    u01 += u00;
194
1.31M
    u11 += u10;
195
1.31M
  }
196
1.68M
      else
197
1.68M
  {
198
1.68M
    mp_double_limb_t rq = div1 (ah, bh);
199
1.68M
    mp_limb_t q = rq.d1;
200
1.68M
    ah = rq.d0;
201
202
1.68M
    if (ah < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2 + 1)))
203
92.0k
      {
204
        /* A is too small, but q is correct. */
205
92.0k
        u01 += q * u00;
206
92.0k
        u11 += q * u10;
207
92.0k
        break;
208
92.0k
      }
209
1.59M
    q++;
210
1.59M
    u01 += q * u00;
211
1.59M
    u11 += q * u10;
212
1.59M
  }
213
3.07M
    subtract_a1:
214
3.07M
      ASSERT (bh >= ah);
215
216
3.07M
      bh -= ah;
217
3.07M
      if (bh < (CNST_LIMB (1) << (GMP_LIMB_BITS / 2 + 1)))
218
77.2k
  break;
219
220
2.99M
      if (bh <= ah)
221
1.19M
  {
222
    /* Use q = 1 */
223
1.19M
    u00 += u01;
224
1.19M
    u10 += u11;
225
1.19M
  }
226
1.79M
      else
227
1.79M
  {
228
1.79M
    mp_double_limb_t rq = div1 (bh, ah);
229
1.79M
    mp_limb_t q = rq.d1;
230
1.79M
    bh = rq.d0;
231
232
1.79M
    if (bh < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2 + 1)))
233
92.2k
      {
234
        /* B is too small, but q is correct. */
235
92.2k
        u00 += q * u01;
236
92.2k
        u10 += q * u11;
237
92.2k
        break;
238
92.2k
      }
239
1.70M
    q++;
240
1.70M
    u00 += q * u01;
241
1.70M
    u10 += q * u11;
242
1.70M
  }
243
2.99M
    }
244
245
366k
 done:
246
366k
  M->u[0][0] = u00; M->u[0][1] = u01;
247
366k
  M->u[1][0] = u10; M->u[1][1] = u11;
248
249
366k
  return 1;
250
195k
}
251
252
/* Sets (r;b) = (a;b) M, with M = (u00, u01; u10, u11). Vector must
253
 * have space for n + 1 limbs. Uses three buffers to avoid a copy*/
254
mp_size_t
255
mpn_hgcd_mul_matrix1_vector (const struct hgcd_matrix1 *M,
256
           mp_ptr rp, mp_srcptr ap, mp_ptr bp, mp_size_t n)
257
366k
{
258
366k
  mp_limb_t ah, bh;
259
260
  /* Compute (r,b) <-- (u00 a + u10 b, u01 a + u11 b) as
261
262
     r  = u00 * a
263
     r += u10 * b
264
     b *= u11
265
     b += u01 * a
266
  */
267
268
#if HAVE_NATIVE_mpn_addaddmul_1msb0
269
  ah = mpn_addaddmul_1msb0 (rp, ap, bp, n, M->u[0][0], M->u[1][0]);
270
  bh = mpn_addaddmul_1msb0 (bp, bp, ap, n, M->u[1][1], M->u[0][1]);
271
#else
272
366k
  ah =     mpn_mul_1 (rp, ap, n, M->u[0][0]);
273
366k
  ah += mpn_addmul_1 (rp, bp, n, M->u[1][0]);
274
275
366k
  bh =     mpn_mul_1 (bp, bp, n, M->u[1][1]);
276
366k
  bh += mpn_addmul_1 (bp, ap, n, M->u[0][1]);
277
366k
#endif
278
366k
  rp[n] = ah;
279
366k
  bp[n] = bh;
280
281
366k
  n += (ah | bh) > 0;
282
366k
  return n;
283
366k
}