xref: /netbsd-src/external/lgpl3/mpfr/dist/src/get_z_2exp.c (revision ba125506a622fe649968631a56eba5d42ff57863)
1*ba125506Smrg /* mpfr_get_z_2exp -- get a multiple-precision integer and an exponent
2*ba125506Smrg                       from a floating-point number
3*ba125506Smrg 
4*ba125506Smrg Copyright 2000-2023 Free Software Foundation, Inc.
5*ba125506Smrg Contributed by the AriC and Caramba projects, INRIA.
6*ba125506Smrg 
7*ba125506Smrg This file is part of the GNU MPFR Library.
8*ba125506Smrg 
9*ba125506Smrg The GNU MPFR Library is free software; you can redistribute it and/or modify
10*ba125506Smrg it under the terms of the GNU Lesser General Public License as published by
11*ba125506Smrg the Free Software Foundation; either version 3 of the License, or (at your
12*ba125506Smrg option) any later version.
13*ba125506Smrg 
14*ba125506Smrg The GNU MPFR Library is distributed in the hope that it will be useful, but
15*ba125506Smrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16*ba125506Smrg or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17*ba125506Smrg License for more details.
18*ba125506Smrg 
19*ba125506Smrg You should have received a copy of the GNU Lesser General Public License
20*ba125506Smrg along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
21*ba125506Smrg https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
22*ba125506Smrg 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
23*ba125506Smrg 
24*ba125506Smrg #include "mpfr-impl.h"
25*ba125506Smrg 
26*ba125506Smrg /* puts the significand of f into z, and returns 'exp' such that f = z * 2^exp
27*ba125506Smrg  *
28*ba125506Smrg  * 0 doesn't have an exponent, therefore the returned exponent in this case
29*ba125506Smrg  * isn't really important. We choose to return __gmpfr_emin because
30*ba125506Smrg  *   1) it is in the exponent range [__gmpfr_emin,__gmpfr_emax],
31*ba125506Smrg  *   2) the smaller a number is (in absolute value), the smaller its
32*ba125506Smrg  *      exponent is. In other words, the f -> exp function is monotonous
33*ba125506Smrg  *      on non-negative numbers. --> This is WRONG since the returned
34*ba125506Smrg  *      exponent is not necessarily in the exponent range!
35*ba125506Smrg  * Note that this is different from the C function frexp().
36*ba125506Smrg  *
37*ba125506Smrg  * For NaN and infinities, we choose to set z = 0 (neutral value).
38*ba125506Smrg  * The exponent doesn't really matter, so let's keep __gmpfr_emin
39*ba125506Smrg  * for consistency. The erange flag is set.
40*ba125506Smrg  */
41*ba125506Smrg 
42*ba125506Smrg /* MPFR_LARGE_EXP can be defined when mpfr_exp_t is guaranteed to have
43*ba125506Smrg    at least 64 bits (in a portable way). */
44*ba125506Smrg #if GMP_NUMB_BITS >= 64
45*ba125506Smrg /* Now, we know that the constant below is supported by the compiler. */
46*ba125506Smrg # if _MPFR_EXP_FORMAT >= 3 && LONG_MAX >= 9223372036854775807
47*ba125506Smrg #  define MPFR_LARGE_EXP 1
48*ba125506Smrg # endif
49*ba125506Smrg #endif
50*ba125506Smrg 
51*ba125506Smrg mpfr_exp_t
mpfr_get_z_2exp(mpz_ptr z,mpfr_srcptr f)52*ba125506Smrg mpfr_get_z_2exp (mpz_ptr z, mpfr_srcptr f)
53*ba125506Smrg {
54*ba125506Smrg   mp_size_t fn;
55*ba125506Smrg   int sh;
56*ba125506Smrg 
57*ba125506Smrg   if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (f)))
58*ba125506Smrg     {
59*ba125506Smrg       if (MPFR_UNLIKELY (MPFR_NOTZERO (f)))
60*ba125506Smrg         MPFR_SET_ERANGEFLAG ();
61*ba125506Smrg       mpz_set_ui (z, 0);
62*ba125506Smrg       return __gmpfr_emin;
63*ba125506Smrg     }
64*ba125506Smrg 
65*ba125506Smrg   fn = MPFR_LIMB_SIZE(f);
66*ba125506Smrg 
67*ba125506Smrg   /* FIXME: temporary assert for security. Too large values should
68*ba125506Smrg      probably be handled like infinities. */
69*ba125506Smrg   MPFR_ASSERTN (fn <= INT_MAX);  /* due to SIZ(z) being an int */
70*ba125506Smrg 
71*ba125506Smrg   /* check whether allocated space for z is enough */
72*ba125506Smrg   mpz_realloc2 (z, (mp_bitcnt_t) fn * GMP_NUMB_BITS);
73*ba125506Smrg 
74*ba125506Smrg   MPFR_UNSIGNED_MINUS_MODULO (sh, MPFR_PREC (f));
75*ba125506Smrg   if (MPFR_LIKELY (sh))
76*ba125506Smrg     mpn_rshift (PTR (z), MPFR_MANT (f), fn, sh);
77*ba125506Smrg   else
78*ba125506Smrg     MPN_COPY (PTR (z), MPFR_MANT (f), fn);
79*ba125506Smrg 
80*ba125506Smrg   SIZ(z) = MPFR_IS_NEG (f) ? -fn : fn;
81*ba125506Smrg 
82*ba125506Smrg #ifndef MPFR_LARGE_EXP
83*ba125506Smrg   /* If mpfr_exp_t has 64 bits, then MPFR_GET_EXP(f) >= MPFR_EMIN_MIN = 1-2^62
84*ba125506Smrg      and MPFR_EXP_MIN <= 1-2^63, thus the following implies PREC(f) > 2^62,
85*ba125506Smrg      which is impossible due to memory constraints. */
86*ba125506Smrg   if (MPFR_UNLIKELY ((mpfr_uexp_t) MPFR_GET_EXP (f) - MPFR_EXP_MIN
87*ba125506Smrg                      < (mpfr_uexp_t) MPFR_PREC (f)))
88*ba125506Smrg     {
89*ba125506Smrg       /* The exponent isn't representable in an mpfr_exp_t. */
90*ba125506Smrg       MPFR_SET_ERANGEFLAG ();
91*ba125506Smrg       return MPFR_EXP_MIN;
92*ba125506Smrg     }
93*ba125506Smrg #endif
94*ba125506Smrg 
95*ba125506Smrg   return MPFR_GET_EXP (f) - MPFR_PREC (f);
96*ba125506Smrg }
97