Coverage Report

Created: 2025-11-16 06:46

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