xref: /netbsd-src/external/lgpl3/mpfr/dist/src/set_z_2exp.c (revision ba125506a622fe649968631a56eba5d42ff57863)
1 /* mpfr_set_z_2exp -- set a floating-point number from a multiple-precision
2                       integer and an exponent
3 
4 Copyright 1999-2023 Free Software Foundation, Inc.
5 Contributed by the AriC and Caramba projects, INRIA.
6 
7 This file is part of the GNU MPFR Library.
8 
9 The GNU MPFR Library is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or (at your
12 option) any later version.
13 
14 The GNU MPFR Library is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17 License for more details.
18 
19 You should have received a copy of the GNU Lesser General Public License
20 along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
21 https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
22 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
23 
24 #define MPFR_NEED_LONGLONG_H
25 #include "mpfr-impl.h"
26 
27 /* set f to the integer z multiplied by 2^e */
28 int
mpfr_set_z_2exp(mpfr_ptr f,mpz_srcptr z,mpfr_exp_t e,mpfr_rnd_t rnd_mode)29 mpfr_set_z_2exp (mpfr_ptr f, mpz_srcptr z, mpfr_exp_t e, mpfr_rnd_t rnd_mode)
30 {
31   mp_size_t fn, zn, dif;
32   int k, sign_z, inex;
33   mp_limb_t *fp, *zp;
34   mpfr_exp_t exp, nmax;
35   mpfr_uexp_t uexp;
36 
37   sign_z = mpz_sgn (z);
38   if (MPFR_UNLIKELY (sign_z == 0)) /* ignore the exponent for 0 */
39     {
40       MPFR_SET_ZERO(f);
41       MPFR_SET_POS(f);
42       MPFR_RET(0);
43     }
44   MPFR_ASSERTD (sign_z == MPFR_SIGN_POS || sign_z == MPFR_SIGN_NEG);
45 
46   zn = ABSIZ(z); /* limb size of z */
47   MPFR_ASSERTD (zn >= 1);
48   nmax = MPFR_EMAX_MAX / GMP_NUMB_BITS + 1;
49   /* Detect early overflow with zn + en > nmax,
50      where en = floor(e / GMP_NUMB_BITS).
51      This is checked without an integer overflow (even assuming some
52      future version of GMP, where limitations may be removed). */
53   if (MPFR_UNLIKELY (e >= 0 ?
54                      zn > nmax - e / GMP_NUMB_BITS :
55                      zn + (e + 1) / GMP_NUMB_BITS - 1 > nmax))
56     return mpfr_overflow (f, rnd_mode, sign_z);
57   /* because zn + en >= MPFR_EMAX_MAX / GMP_NUMB_BITS + 2
58      implies (zn + en) * GMP_NUMB_BITS >= MPFR_EMAX_MAX + GMP_NUMB_BITS + 1
59      and exp = zn * GMP_NUMB_BITS + e - k
60              >= (zn + en) * GMP_NUMB_BITS - k > MPFR_EMAX_MAX */
61 
62   fp = MPFR_MANT (f);
63   fn = MPFR_LIMB_SIZE (f);
64   dif = zn - fn;
65   zp = PTR(z);
66   count_leading_zeros (k, zp[zn-1]);
67 
68   /* now zn + en <= MPFR_EMAX_MAX / GMP_NUMB_BITS + 1
69      thus (zn + en) * GMP_NUMB_BITS <= MPFR_EMAX_MAX + GMP_NUMB_BITS
70      and exp = zn * GMP_NUMB_BITS + e - k
71              <= (zn + en) * GMP_NUMB_BITS - k + GMP_NUMB_BITS - 1
72              <= MPFR_EMAX_MAX + 2 * GMP_NUMB_BITS - 1 */
73   /* We need to compute exp = zn * GMP_NUMB_BITS + e - k with well-defined
74      operations (no integer overflows / no implementation-defined results).
75      The mathematical result of zn * GMP_NUMB_BITS may be larger than
76      the largest value of mpfr_exp_t while exp could still be less than
77      __gmpfr_emax. Thanks to early overflow detection, we can compute the
78      result in modular arithmetic, using mpfr_uexp_t, and convert it to
79      mpfr_exp_t. */
80   uexp = (mpfr_uexp_t) zn * GMP_NUMB_BITS + (mpfr_uexp_t) e - k;
81 
82   /* Convert to signed in a portable way (see doc/README.dev).
83      On most platforms, this can be optimized to identity (no-op). */
84   exp = uexp > MPFR_EXP_MAX ? -1 - (mpfr_exp_t) ~uexp : (mpfr_exp_t) uexp;
85 
86   /* The exponent will be exp or exp + 1 (due to rounding) */
87 
88   if (MPFR_UNLIKELY (exp > __gmpfr_emax))
89     return mpfr_overflow (f, rnd_mode, sign_z);
90   if (MPFR_UNLIKELY (exp + 1 < __gmpfr_emin))
91     return mpfr_underflow (f, rnd_mode == MPFR_RNDN ? MPFR_RNDZ : rnd_mode,
92                            sign_z);
93 
94   if (MPFR_LIKELY (dif >= 0))
95     {
96       mp_limb_t rb, sb, ulp;
97       int sh;
98 
99       /* number has to be truncated */
100       if (MPFR_LIKELY (k != 0))
101         {
102           mpn_lshift (fp, &zp[dif], fn, k);
103           if (MPFR_UNLIKELY (dif > 0))
104             fp[0] |= zp[dif - 1] >> (GMP_NUMB_BITS - k);
105         }
106       else
107         MPN_COPY (fp, zp + dif, fn);
108 
109       /* Compute Rounding Bit and Sticky Bit */
110       MPFR_UNSIGNED_MINUS_MODULO (sh, MPFR_PREC (f) );
111       if (MPFR_LIKELY (sh != 0))
112         {
113           mp_limb_t mask = MPFR_LIMB_ONE << (sh-1);
114           mp_limb_t limb = fp[0];
115           rb = limb & mask;
116           sb = limb & (mask-1);
117           ulp = 2*mask;
118           fp[0] = limb & ~(ulp-1);
119         }
120       else /* sh == 0 */
121         {
122           mp_limb_t mask = MPFR_LIMB_ONE << (GMP_NUMB_BITS - 1 - k);
123           if (MPFR_UNLIKELY (dif > 0))
124             {
125               rb = zp[--dif] & mask;
126               sb = zp[dif] & (mask-1);
127             }
128           else
129             rb = sb = 0;
130           k = 0;
131           ulp = MPFR_LIMB_ONE;
132         }
133       if (MPFR_UNLIKELY (sb == 0 && dif > 0))
134         {
135           sb = zp[--dif];
136           if (MPFR_LIKELY (k != 0))
137             sb &= MPFR_LIMB_MASK (GMP_NUMB_BITS - k);
138           if (MPFR_UNLIKELY (sb == 0) && MPFR_LIKELY (dif > 0))
139             do {
140               sb = zp[--dif];
141             } while (dif > 0 && sb == 0);
142         }
143 
144       /* Rounding */
145       if (MPFR_LIKELY (rnd_mode == MPFR_RNDN))
146         {
147           if (rb == 0 || MPFR_UNLIKELY (sb == 0 && (fp[0] & ulp) == 0))
148             goto trunc;
149           else
150             goto addoneulp;
151         }
152       else /* Not Nearest */
153         {
154           if (MPFR_LIKELY (MPFR_IS_LIKE_RNDZ (rnd_mode, sign_z < 0))
155               || MPFR_UNLIKELY ( (sb | rb) == 0 ))
156             goto trunc;
157           else
158             goto addoneulp;
159         }
160 
161     trunc:
162       inex = - ((sb | rb) != 0);
163       goto end;
164 
165     addoneulp:
166       inex = 1;
167       if (MPFR_UNLIKELY (mpn_add_1 (fp, fp, fn, ulp)))
168         {
169           /* Pow 2 case */
170           if (MPFR_UNLIKELY (exp == __gmpfr_emax))
171             return mpfr_overflow (f, rnd_mode, sign_z);
172           exp ++;
173           fp[fn-1] = MPFR_LIMB_HIGHBIT;
174         }
175     end:
176       (void) 0;
177     }
178   else   /* dif < 0: Mantissa F is strictly bigger than z's one */
179     {
180       if (MPFR_LIKELY (k != 0))
181         mpn_lshift (fp - dif, zp, zn, k);
182       else
183         MPN_COPY (fp - dif, zp, zn);
184       /* fill with zeroes */
185       MPN_ZERO (fp, -dif);
186       inex = 0; /* result is exact */
187     }
188 
189   if (MPFR_UNLIKELY (exp < __gmpfr_emin))
190     {
191       if (rnd_mode == MPFR_RNDN && inex == 0 && mpfr_powerof2_raw (f))
192         rnd_mode = MPFR_RNDZ;
193       return mpfr_underflow (f, rnd_mode, sign_z);
194     }
195 
196   MPFR_SET_EXP (f, exp);
197   MPFR_SET_SIGN (f, sign_z);
198   MPFR_RET (inex*sign_z);
199 }
200