xref: /netbsd-src/external/lgpl3/mpfr/dist/src/div_ui.c (revision ec6772edaf0cdcb5f52a48f4aca5e33a8fb8ecfd)
1 /* mpfr_div_ui -- divide a floating-point number by a machine integer
2 
3 Copyright 1999-2023 Free Software Foundation, Inc.
4 Contributed by the AriC and Caramba projects, INRIA.
5 
6 This file is part of the GNU MPFR Library.
7 
8 The GNU MPFR Library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 The GNU MPFR Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16 License for more details.
17 
18 You should have received a copy of the GNU Lesser General Public License
19 along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
20 https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
21 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
22 
23 #define MPFR_NEED_LONGLONG_H
24 #include "mpfr-impl.h"
25 
26 #ifdef MPFR_COV_CHECK
27 int __gmpfr_cov_div_ui_sb[10][2] = { 0 };
28 #endif
29 
30 /* returns 0 if result exact, non-zero otherwise */
31 #undef mpfr_div_ui
32 MPFR_HOT_FUNCTION_ATTR int
mpfr_div_ui(mpfr_ptr y,mpfr_srcptr x,unsigned long int u,mpfr_rnd_t rnd_mode)33 mpfr_div_ui (mpfr_ptr y, mpfr_srcptr x, unsigned long int u,
34              mpfr_rnd_t rnd_mode)
35 {
36   int inexact;
37 
38 #ifdef MPFR_LONG_WITHIN_LIMB
39 
40   int sh;
41   mp_size_t i, xn, yn, dif;
42   mp_limb_t *xp, *yp, *tmp, c, d;
43   mpfr_exp_t exp;
44   mp_limb_t rb; /* round bit */
45   mp_limb_t sb; /* sticky bit */
46   MPFR_TMP_DECL(marker);
47 
48   MPFR_LOG_FUNC
49     (("x[%Pd]=%.*Rg u=%lu rnd=%d",
50       mpfr_get_prec(x), mpfr_log_prec, x, u, rnd_mode),
51      ("y[%Pd]=%.*Rg inexact=%d",
52       mpfr_get_prec(y), mpfr_log_prec, y, inexact));
53 
54   if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
55     {
56       if (MPFR_IS_NAN (x))
57         {
58           MPFR_SET_NAN (y);
59           MPFR_RET_NAN;
60         }
61       else if (MPFR_IS_INF (x))
62         {
63           MPFR_SET_INF (y);
64           MPFR_SET_SAME_SIGN (y, x);
65           MPFR_RET (0);
66         }
67       else
68         {
69           MPFR_ASSERTD (MPFR_IS_ZERO (x));
70           if (u == 0) /* 0/0 is NaN */
71             {
72               MPFR_SET_NAN (y);
73               MPFR_RET_NAN;
74             }
75           else
76             {
77               MPFR_SET_ZERO(y);
78               MPFR_SET_SAME_SIGN (y, x);
79               MPFR_RET(0);
80             }
81         }
82     }
83   else if (MPFR_UNLIKELY (u <= 1))
84     {
85       if (u < 1)
86         {
87           /* x/0 is Inf since x != 0 */
88           MPFR_SET_INF (y);
89           MPFR_SET_SAME_SIGN (y, x);
90           MPFR_SET_DIVBY0 ();
91           MPFR_RET (0);
92         }
93       else /* y = x/1 = x */
94         return mpfr_set (y, x, rnd_mode);
95     }
96   else if (MPFR_UNLIKELY (IS_POW2 (u)))
97     return mpfr_div_2si (y, x, MPFR_INT_CEIL_LOG2 (u), rnd_mode);
98 
99   MPFR_SET_SAME_SIGN (y, x);
100 
101   MPFR_TMP_MARK (marker);
102 
103   xn = MPFR_LIMB_SIZE (x);
104   yn = MPFR_LIMB_SIZE (y);
105 
106   xp = MPFR_MANT (x);
107   yp = MPFR_MANT (y);
108   exp = MPFR_GET_EXP (x);
109 
110   dif = yn + 1 - xn;
111 
112   /* we need to store yn + 1 = xn + dif limbs of the quotient */
113   tmp = MPFR_TMP_LIMBS_ALLOC (yn + 1);
114 
115   /* Notation: {p, n} denotes the integer formed by the n limbs
116      from p[0] to p[n-1]. Let B = 2^GMP_NUMB_BITS.
117      One has: 0 <= {p, n} < B^n. */
118 
119   if (dif >= 0)
120     {
121       c = mpn_divrem_1 (tmp, dif, xp, xn, u); /* used all the dividend */
122       /* {xp, xn} = ({tmp, xn+dif} * u + c) * B^(-dif)
123                   = ({tmp, yn+1} * u + c) * B^(-dif) */
124     }
125   else /* dif < 0, i.e. xn > yn+1; ignore the (-dif) low limbs from x */
126     {
127       c = mpn_divrem_1 (tmp, 0, xp - dif, yn + 1, u);
128       /* {xp-dif, yn+1} = {tmp, yn+1} * u + c
129          thus
130          {xp, xn} = {xp, -dif} + {xp-dif, yn+1} * B^(-dif)
131                   = {xp, -dif} + ({tmp, yn+1} * u + c) * B^(-dif) */
132     }
133 
134   /* Let r = {xp, -dif} / B^(-dif) if dif < 0, r = 0 otherwise; 0 <= r < 1.
135      Then {xp, xn} = ({tmp, yn+1} * u + c + r) * B^(-dif).
136      x / u = ({xp, xn} / u) * B^(-xn) * 2^exp
137            = ({tmp, yn+1} + (c + r) / u) * B^(-(yn+1)) * 2^exp
138      where 0 <= (c + r) / u < 1. */
139 
140   for (sb = 0, i = 0; sb == 0 && i < -dif; i++)
141     if (xp[i])
142       sb = 1;
143   /* sb != 0 iff r != 0 */
144 
145   /*
146      If the highest limb of the result is 0 (xp[xn-1] < u), remove it.
147      Otherwise, compute the left shift to be performed to normalize.
148      In the latter case, we discard some low bits computed. They
149      contain information useful for the rounding, hence the updating
150      of middle and inexact.
151   */
152 
153   MPFR_UNSIGNED_MINUS_MODULO (sh, MPFR_PREC (y));
154   /* sh: number of the trailing bits of y */
155 
156   if (tmp[yn] == 0)
157     {
158       MPN_COPY(yp, tmp, yn);
159       exp -= GMP_NUMB_BITS;
160       if (sh == 0) /* round bit is 1 iff (c + r) / u >= 1/2 */
161         {
162           /* In this case tmp[yn]=0 and sh=0, the round bit is not in
163              {tmp,yn+1}. It is 1 iff 2*(c+r) - u >= 0. This means that in
164              some cases, we should look at the most significant bit of r. */
165           if (c >= u - c) /* i.e. 2c >= u: round bit is always 1 */
166             {
167               rb = 1;
168               /* The sticky bit is 1 unless 2c-u = 0 and r = 0. */
169               sb |= 2 * c - u;
170               MPFR_COV_SET (div_ui_sb[0][!!sb]);
171             }
172           else /* 2*c < u */
173             {
174               /* The round bit is 1 iff r >= 1/2 and 2*(c+1/2) = u. */
175               rb = (c == u/2) && (dif < 0) && (xp[-dif-1] & MPFR_LIMB_HIGHBIT);
176               /* If rb is set, we need to recompute sb, since it might have
177                  taken into account the msb of xp[-dif-1]. */
178               if (rb)
179                 {
180                   sb = xp[-dif-1] << 1; /* discard the most significant bit */
181                   for (i = 0; sb == 0 && i < -dif-1; i++)
182                     if (xp[i])
183                       sb = 1;
184                   /* The dif < -1 case with sb = 0, i.e. [2][0], will
185                      ensure that the body of the loop is covered. */
186                   MPFR_COV_SET (div_ui_sb[1 + (dif < -1)][!!sb]);
187                 }
188               else
189                 {
190                   sb |= c;
191                   MPFR_COV_SET (div_ui_sb[3][!!sb]);
192                 }
193             }
194         }
195       else
196         {
197           /* round bit is in tmp[0] */
198           rb = tmp[0] & (MPFR_LIMB_ONE << (sh - 1));
199           sb |= (tmp[0] & MPFR_LIMB_MASK(sh - 1)) | c;
200           MPFR_COV_SET (div_ui_sb[4+!!rb][!!sb]);
201         }
202     }
203   else  /* tmp[yn] != 0 */
204     {
205       int shlz;
206       mp_limb_t w;
207 
208       MPFR_ASSERTD (tmp[yn] != 0);
209       count_leading_zeros (shlz, tmp[yn]);
210 
211       MPFR_ASSERTD (u >= 2);    /* see special cases at the beginning */
212       MPFR_ASSERTD (shlz > 0);  /* since u >= 2 */
213 
214       /* shift left to normalize */
215       w = tmp[0] << shlz;
216       mpn_lshift (yp, tmp + 1, yn, shlz);
217       yp[0] |= tmp[0] >> (GMP_NUMB_BITS - shlz);
218       /* now {yp, yn} is the approximate quotient, w is the next limb */
219 
220       if (sh == 0) /* round bit is upper bit from w */
221         {
222           rb = w & MPFR_LIMB_HIGHBIT;
223           sb |= (w - rb) | c;
224           MPFR_COV_SET (div_ui_sb[6+!!rb][!!sb]);
225         }
226       else
227         {
228           rb = yp[0] & (MPFR_LIMB_ONE << (sh - 1));
229           sb |= (yp[0] & MPFR_LIMB_MASK(sh - 1)) | w | c;
230           MPFR_COV_SET (div_ui_sb[8+!!rb][!!sb]);
231         }
232 
233       exp -= shlz;
234     }
235 
236   d = yp[0] & MPFR_LIMB_MASK (sh);
237   yp[0] ^= d; /* clear the lowest sh bits */
238 
239   MPFR_TMP_FREE (marker);
240 
241   if (MPFR_UNLIKELY (exp < __gmpfr_emin - 1))
242     return mpfr_underflow (y, rnd_mode == MPFR_RNDN ? MPFR_RNDZ : rnd_mode,
243                            MPFR_SIGN (y));
244 
245   if (MPFR_UNLIKELY (rb == 0 && sb == 0))
246     inexact = 0;  /* result is exact */
247   else
248     {
249       int nexttoinf;
250 
251       MPFR_UPDATE2_RND_MODE (rnd_mode, MPFR_SIGN (y));
252       switch (rnd_mode)
253         {
254         case MPFR_RNDZ:
255         case MPFR_RNDF:
256           inexact = - MPFR_INT_SIGN (y);  /* result is inexact */
257           nexttoinf = 0;
258           break;
259 
260         case MPFR_RNDA:
261           inexact = MPFR_INT_SIGN (y);
262           nexttoinf = 1;
263           break;
264 
265         default: /* should be MPFR_RNDN */
266           MPFR_ASSERTD (rnd_mode == MPFR_RNDN);
267           /* We have one more significant bit in yn. */
268           if (rb == 0)
269             {
270               inexact = - MPFR_INT_SIGN (y);
271               nexttoinf = 0;
272             }
273           else if (sb != 0) /* necessarily rb != 0 */
274             {
275               inexact = MPFR_INT_SIGN (y);
276               nexttoinf = 1;
277             }
278           else /* middle case */
279             {
280               if (yp[0] & (MPFR_LIMB_ONE << sh))
281                 {
282                   inexact = MPFR_INT_SIGN (y);
283                   nexttoinf = 1;
284                 }
285               else
286                 {
287                   inexact = - MPFR_INT_SIGN (y);
288                   nexttoinf = 0;
289                 }
290             }
291         }
292       if (nexttoinf &&
293           MPFR_UNLIKELY (mpn_add_1 (yp, yp, yn, MPFR_LIMB_ONE << sh)))
294         {
295           exp++;
296           yp[yn-1] = MPFR_LIMB_HIGHBIT;
297         }
298     }
299 
300   /* Set the exponent. Warning! One may still have an underflow. */
301   MPFR_EXP (y) = exp;
302 #else /* MPFR_LONG_WITHIN_LIMB */
303   mpfr_t uu;
304   MPFR_SAVE_EXPO_DECL (expo);
305 
306   MPFR_SAVE_EXPO_MARK (expo);
307   mpfr_init2 (uu, sizeof (unsigned long) * CHAR_BIT);
308   mpfr_set_ui (uu, u, MPFR_RNDZ);
309   inexact = mpfr_div (y, x, uu, rnd_mode);
310   mpfr_clear (uu);
311   MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, __gmpfr_flags);
312   MPFR_SAVE_EXPO_FREE (expo);
313 #endif
314 
315   return mpfr_check_range (y, inexact, rnd_mode);
316 }
317