Coverage Report

Created: 2024-06-28 06:39

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