Coverage Report

Created: 2026-11-12 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gmp/mpn/dcpi1_div_qr.c
Line
Count
Source
1
/* mpn_dcpi1_div_qr_n -- recursive divide-and-conquer division for arbitrary
2
   size operands.
3
4
   Contributed to the GNU project by Torbjorn Granlund.
5
6
   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
7
   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
8
   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
9
10
Copyright 2006, 2007, 2009 Free Software Foundation, Inc.
11
12
This file is part of the GNU MP Library.
13
14
The GNU MP Library is free software; you can redistribute it and/or modify
15
it under the terms of either:
16
17
  * the GNU Lesser General Public License as published by the Free
18
    Software Foundation; either version 3 of the License, or (at your
19
    option) any later version.
20
21
or
22
23
  * the GNU General Public License as published by the Free Software
24
    Foundation; either version 2 of the License, or (at your option) any
25
    later version.
26
27
or both in parallel, as here.
28
29
The GNU MP Library is distributed in the hope that it will be useful, but
30
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
31
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
32
for more details.
33
34
You should have received copies of the GNU General Public License and the
35
GNU Lesser General Public License along with the GNU MP Library.  If not,
36
see https://www.gnu.org/licenses/.  */
37
38
#include "gmp-impl.h"
39
#include "longlong.h"
40
41
42
mp_limb_t
43
mpn_dcpi1_div_qr_n (mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n,
44
        gmp_pi1_t *dinv, mp_ptr tp)
45
2.29k
{
46
2.29k
  mp_size_t lo, hi;
47
2.29k
  mp_limb_t cy, qh, ql;
48
49
2.29k
  lo = n >> 1;      /* floor(n/2) */
50
2.29k
  hi = n - lo;      /* ceil(n/2) */
51
52
2.29k
  if (BELOW_THRESHOLD (hi, DC_DIV_QR_THRESHOLD))
53
1.87k
    qh = mpn_sbpi1_div_qr (qp + lo, np + 2 * lo, 2 * hi, dp + lo, hi, dinv->inv32);
54
418
  else
55
418
    qh = mpn_dcpi1_div_qr_n (qp + lo, np + 2 * lo, dp + lo, hi, dinv, tp);
56
57
2.29k
  mpn_mul (tp, qp + lo, hi, dp, lo);
58
59
2.29k
  cy = mpn_sub_n (np + lo, np + lo, tp, n);
60
2.29k
  if (qh != 0)
61
24
    cy += mpn_sub_n (np + n, np + n, dp, lo);
62
63
2.88k
  while (cy != 0)
64
589
    {
65
589
      qh -= mpn_sub_1 (qp + lo, qp + lo, hi, 1);
66
589
      cy -= mpn_add_n (np + lo, np + lo, dp, n);
67
589
    }
68
69
2.29k
  if (BELOW_THRESHOLD (lo, DC_DIV_QR_THRESHOLD))
70
1.87k
    ql = mpn_sbpi1_div_qr (qp, np + hi, 2 * lo, dp + hi, lo, dinv->inv32);
71
418
  else
72
418
    ql = mpn_dcpi1_div_qr_n (qp, np + hi, dp + hi, lo, dinv, tp);
73
74
2.29k
  mpn_mul (tp, dp, hi, qp, lo);
75
76
2.29k
  cy = mpn_sub_n (np, np, tp, n);
77
2.29k
  if (ql != 0)
78
4
    cy += mpn_sub_n (np + lo, np + lo, dp, hi);
79
80
2.73k
  while (cy != 0)
81
438
    {
82
438
      mpn_sub_1 (qp, qp, lo, 1);
83
438
      cy -= mpn_add_n (np, np, dp, n);
84
438
    }
85
86
2.29k
  return qh;
87
2.29k
}
88
89
mp_limb_t
90
mpn_dcpi1_div_qr (mp_ptr qp,
91
      mp_ptr np, mp_size_t nn,
92
      mp_srcptr dp, mp_size_t dn,
93
      gmp_pi1_t *dinv)
94
1.41k
{
95
1.41k
  mp_size_t qn;
96
1.41k
  mp_limb_t qh, cy;
97
1.41k
  mp_ptr tp;
98
1.41k
  TMP_DECL;
99
100
1.41k
  TMP_MARK;
101
102
1.41k
  ASSERT (dn >= 6);   /* to adhere to mpn_sbpi1_div_qr's limits */
103
1.41k
  ASSERT (nn - dn >= 3);  /* to adhere to mpn_sbpi1_div_qr's limits */
104
1.41k
  ASSERT (dp[dn-1] & GMP_NUMB_HIGHBIT);
105
106
1.41k
  tp = TMP_ALLOC_LIMBS (dn);
107
108
1.41k
  qn = nn - dn;
109
1.41k
  qp += qn;
110
1.41k
  np += nn;
111
1.41k
  dp += dn;
112
113
1.41k
  if (qn > dn)
114
252
    {
115
      /* Reduce qn mod dn without division, optimizing small operations.  */
116
252
      do
117
287
  qn -= dn;
118
287
      while (qn > dn);
119
120
252
      qp -= qn;     /* point at low limb of next quotient block */
121
252
      np -= qn;     /* point in the middle of partial remainder */
122
123
      /* Perform the typically smaller block first.  */
124
252
      if (qn == 1)
125
175
  {
126
175
    mp_limb_t q, n2, n1, n0, d1, d0;
127
128
    /* Handle qh up front, for simplicity. */
129
175
    qh = mpn_cmp (np - dn + 1, dp - dn, dn) >= 0;
130
175
    if (qh)
131
0
      ASSERT_NOCARRY (mpn_sub_n (np - dn + 1, np - dn + 1, dp - dn, dn));
132
133
    /* A single iteration of schoolbook: One 3/2 division,
134
       followed by the bignum update and adjustment. */
135
175
    n2 = np[0];
136
175
    n1 = np[-1];
137
175
    n0 = np[-2];
138
175
    d1 = dp[-1];
139
175
    d0 = dp[-2];
140
141
175
    ASSERT (n2 < d1 || (n2 == d1 && n1 <= d0));
142
143
175
    if (UNLIKELY (n2 == d1) && n1 == d0)
144
0
      {
145
0
        q = GMP_NUMB_MASK;
146
0
        cy = mpn_submul_1 (np - dn, dp - dn, dn, q);
147
0
        ASSERT (cy == n2);
148
0
      }
149
175
    else
150
175
      {
151
175
        udiv_qr_3by2 (q, n1, n0, n2, n1, n0, d1, d0, dinv->inv32);
152
153
175
        if (dn > 2)
154
175
    {
155
175
      mp_limb_t cy, cy1;
156
175
      cy = mpn_submul_1 (np - dn, dp - dn, dn - 2, q);
157
158
175
      cy1 = n0 < cy;
159
175
      n0 = (n0 - cy) & GMP_NUMB_MASK;
160
175
      cy = n1 < cy1;
161
175
      n1 = (n1 - cy1) & GMP_NUMB_MASK;
162
175
      np[-2] = n0;
163
164
175
      if (UNLIKELY (cy != 0))
165
24
        {
166
24
          n1 += d1 + mpn_add_n (np - dn, np - dn, dp - dn, dn - 1);
167
24
          qh -= (q == 0);
168
24
          q = (q - 1) & GMP_NUMB_MASK;
169
24
        }
170
175
    }
171
0
        else
172
0
    np[-2] = n0;
173
174
175
        np[-1] = n1;
175
175
      }
176
175
    qp[0] = q;
177
175
  }
178
77
      else
179
77
  {
180
    /* Do a 2qn / qn division */
181
77
    if (qn == 2)
182
8
      qh = mpn_divrem_2 (qp, 0L, np - 2, 4, dp - 2); /* FIXME: obsolete function. Use 5/3 division? */
183
69
    else if (BELOW_THRESHOLD (qn, DC_DIV_QR_THRESHOLD))
184
62
      qh = mpn_sbpi1_div_qr (qp, np - qn, 2 * qn, dp - qn, qn, dinv->inv32);
185
7
    else
186
7
      qh = mpn_dcpi1_div_qr_n (qp, np - qn, dp - qn, qn, dinv, tp);
187
188
77
    if (qn != dn)
189
75
      {
190
75
        if (qn > dn - qn)
191
11
    mpn_mul (tp, qp, qn, dp - dn, dn - qn);
192
64
        else
193
64
    mpn_mul (tp, dp - dn, dn - qn, qp, qn);
194
195
75
        cy = mpn_sub_n (np - dn, np - dn, tp, dn);
196
75
        if (qh != 0)
197
0
    cy += mpn_sub_n (np - dn + qn, np - dn + qn, dp - dn, dn - qn);
198
199
108
        while (cy != 0)
200
33
    {
201
33
      qh -= mpn_sub_1 (qp, qp, qn, 1);
202
33
      cy -= mpn_add_n (np - dn, np - dn, dp - dn, dn);
203
33
    }
204
75
      }
205
77
  }
206
207
252
      qn = nn - dn - qn;
208
252
      do
209
287
  {
210
287
    qp -= dn;
211
287
    np -= dn;
212
287
    mpn_dcpi1_div_qr_n (qp, np - dn, dp - dn, dn, dinv, tp);
213
287
    qn -= dn;
214
287
  }
215
287
      while (qn > 0);
216
252
    }
217
1.16k
  else
218
1.16k
    {
219
1.16k
      qp -= qn;     /* point at low limb of next quotient block */
220
1.16k
      np -= qn;     /* point in the middle of partial remainder */
221
222
1.16k
      if (BELOW_THRESHOLD (qn, DC_DIV_QR_THRESHOLD))
223
0
  qh = mpn_sbpi1_div_qr (qp, np - qn, 2 * qn, dp - qn, qn, dinv->inv32);
224
1.16k
      else
225
1.16k
  qh = mpn_dcpi1_div_qr_n (qp, np - qn, dp - qn, qn, dinv, tp);
226
227
1.16k
      if (qn != dn)
228
0
  {
229
0
    if (qn > dn - qn)
230
0
      mpn_mul (tp, qp, qn, dp - dn, dn - qn);
231
0
    else
232
0
      mpn_mul (tp, dp - dn, dn - qn, qp, qn);
233
234
0
    cy = mpn_sub_n (np - dn, np - dn, tp, dn);
235
0
    if (qh != 0)
236
0
      cy += mpn_sub_n (np - dn + qn, np - dn + qn, dp - dn, dn - qn);
237
238
0
    while (cy != 0)
239
0
      {
240
0
        qh -= mpn_sub_1 (qp, qp, qn, 1);
241
0
        cy -= mpn_add_n (np - dn, np - dn, dp - dn, dn);
242
0
      }
243
0
  }
244
1.16k
    }
245
246
1.41k
  TMP_FREE;
247
1.41k
  return qh;
248
1.41k
}