Coverage Report

Created: 2026-02-09 06:47

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