Coverage Report

Created: 2026-03-31 06:37

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.14k
{
46
2.14k
  mp_size_t lo, hi;
47
2.14k
  mp_limb_t cy, qh, ql;
48
49
2.14k
  lo = n >> 1;      /* floor(n/2) */
50
2.14k
  hi = n - lo;      /* ceil(n/2) */
51
52
2.14k
  if (BELOW_THRESHOLD (hi, DC_DIV_QR_THRESHOLD))
53
1.75k
    qh = mpn_sbpi1_div_qr (qp + lo, np + 2 * lo, 2 * hi, dp + lo, hi, dinv->inv32);
54
388
  else
55
388
    qh = mpn_dcpi1_div_qr_n (qp + lo, np + 2 * lo, dp + lo, hi, dinv, tp);
56
57
2.14k
  mpn_mul (tp, qp + lo, hi, dp, lo);
58
59
2.14k
  cy = mpn_sub_n (np + lo, np + lo, tp, n);
60
2.14k
  if (qh != 0)
61
23
    cy += mpn_sub_n (np + n, np + n, dp, lo);
62
63
2.74k
  while (cy != 0)
64
593
    {
65
593
      qh -= mpn_sub_1 (qp + lo, qp + lo, hi, 1);
66
593
      cy -= mpn_add_n (np + lo, np + lo, dp, n);
67
593
    }
68
69
2.14k
  if (BELOW_THRESHOLD (lo, DC_DIV_QR_THRESHOLD))
70
1.75k
    ql = mpn_sbpi1_div_qr (qp, np + hi, 2 * lo, dp + hi, lo, dinv->inv32);
71
388
  else
72
388
    ql = mpn_dcpi1_div_qr_n (qp, np + hi, dp + hi, lo, dinv, tp);
73
74
2.14k
  mpn_mul (tp, dp, hi, qp, lo);
75
76
2.14k
  cy = mpn_sub_n (np, np, tp, n);
77
2.14k
  if (ql != 0)
78
5
    cy += mpn_sub_n (np + lo, np + lo, dp, hi);
79
80
2.59k
  while (cy != 0)
81
448
    {
82
448
      mpn_sub_1 (qp, qp, lo, 1);
83
448
      cy -= mpn_add_n (np, np, dp, n);
84
448
    }
85
86
2.14k
  return qh;
87
2.14k
}
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.33k
{
95
1.33k
  mp_size_t qn;
96
1.33k
  mp_limb_t qh, cy;
97
1.33k
  mp_ptr tp;
98
1.33k
  TMP_DECL;
99
100
1.33k
  TMP_MARK;
101
102
1.33k
  ASSERT (dn >= 6);   /* to adhere to mpn_sbpi1_div_qr's limits */
103
1.33k
  ASSERT (nn - dn >= 3);  /* to adhere to mpn_sbpi1_div_qr's limits */
104
1.33k
  ASSERT (dp[dn-1] & GMP_NUMB_HIGHBIT);
105
106
1.33k
  tp = TMP_ALLOC_LIMBS (dn);
107
108
1.33k
  qn = nn - dn;
109
1.33k
  qp += qn;
110
1.33k
  np += nn;
111
1.33k
  dp += dn;
112
113
1.33k
  if (qn > dn)
114
246
    {
115
      /* Reduce qn mod dn without division, optimizing small operations.  */
116
246
      do
117
272
  qn -= dn;
118
272
      while (qn > dn);
119
120
246
      qp -= qn;     /* point at low limb of next quotient block */
121
246
      np -= qn;     /* point in the middle of partial remainder */
122
123
      /* Perform the typically smaller block first.  */
124
246
      if (qn == 1)
125
165
  {
126
165
    mp_limb_t q, n2, n1, n0, d1, d0;
127
128
    /* Handle qh up front, for simplicity. */
129
165
    qh = mpn_cmp (np - dn + 1, dp - dn, dn) >= 0;
130
165
    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
165
    n2 = np[0];
136
165
    n1 = np[-1];
137
165
    n0 = np[-2];
138
165
    d1 = dp[-1];
139
165
    d0 = dp[-2];
140
141
165
    ASSERT (n2 < d1 || (n2 == d1 && n1 <= d0));
142
143
165
    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
165
    else
150
165
      {
151
165
        udiv_qr_3by2 (q, n1, n0, n2, n1, n0, d1, d0, dinv->inv32);
152
153
165
        if (dn > 2)
154
165
    {
155
165
      mp_limb_t cy, cy1;
156
165
      cy = mpn_submul_1 (np - dn, dp - dn, dn - 2, q);
157
158
165
      cy1 = n0 < cy;
159
165
      n0 = (n0 - cy) & GMP_NUMB_MASK;
160
165
      cy = n1 < cy1;
161
165
      n1 = (n1 - cy1) & GMP_NUMB_MASK;
162
165
      np[-2] = n0;
163
164
165
      if (UNLIKELY (cy != 0))
165
22
        {
166
22
          n1 += d1 + mpn_add_n (np - dn, np - dn, dp - dn, dn - 1);
167
22
          qh -= (q == 0);
168
22
          q = (q - 1) & GMP_NUMB_MASK;
169
22
        }
170
165
    }
171
0
        else
172
0
    np[-2] = n0;
173
174
165
        np[-1] = n1;
175
165
      }
176
165
    qp[0] = q;
177
165
  }
178
81
      else
179
81
  {
180
    /* Do a 2qn / qn division */
181
81
    if (qn == 2)
182
7
      qh = mpn_divrem_2 (qp, 0L, np - 2, 4, dp - 2); /* FIXME: obsolete function. Use 5/3 division? */
183
74
    else if (BELOW_THRESHOLD (qn, DC_DIV_QR_THRESHOLD))
184
67
      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
81
    if (qn != dn)
189
79
      {
190
79
        if (qn > dn - qn)
191
11
    mpn_mul (tp, qp, qn, dp - dn, dn - qn);
192
68
        else
193
68
    mpn_mul (tp, dp - dn, dn - qn, qp, qn);
194
195
79
        cy = mpn_sub_n (np - dn, np - dn, tp, dn);
196
79
        if (qh != 0)
197
0
    cy += mpn_sub_n (np - dn + qn, np - dn + qn, dp - dn, dn - qn);
198
199
115
        while (cy != 0)
200
36
    {
201
36
      qh -= mpn_sub_1 (qp, qp, qn, 1);
202
36
      cy -= mpn_add_n (np - dn, np - dn, dp - dn, dn);
203
36
    }
204
79
      }
205
81
  }
206
207
246
      qn = nn - dn - qn;
208
246
      do
209
272
  {
210
272
    qp -= dn;
211
272
    np -= dn;
212
272
    mpn_dcpi1_div_qr_n (qp, np - dn, dp - dn, dn, dinv, tp);
213
272
    qn -= dn;
214
272
  }
215
272
      while (qn > 0);
216
246
    }
217
1.09k
  else
218
1.09k
    {
219
1.09k
      qp -= qn;     /* point at low limb of next quotient block */
220
1.09k
      np -= qn;     /* point in the middle of partial remainder */
221
222
1.09k
      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.09k
      else
225
1.09k
  qh = mpn_dcpi1_div_qr_n (qp, np - qn, dp - qn, qn, dinv, tp);
226
227
1.09k
      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.09k
    }
245
246
1.33k
  TMP_FREE;
247
1.33k
  return qh;
248
1.33k
}