1/* mpfr_get_f -- convert a MPFR number to a GNU MPF number
2
3Copyright 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
4Contributed by the AriC and Caramel projects, INRIA.
5
6This file is part of the GNU MPFR Library.
7
8The GNU MPFR Library is free software; you can redistribute it and/or modify
9it under the terms of the GNU Lesser General Public License as published by
10the Free Software Foundation; either version 3 of the License, or (at your
11option) any later version.
12
13The GNU MPFR Library is distributed in the hope that it will be useful, but
14WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16License for more details.
17
18You should have received a copy of the GNU Lesser General Public License
19along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
20http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
2151 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
22
23#include "mpfr-impl.h"
24
25/* Since MPFR-3.0, return the usual inexact value.
26   The erange flag is set if an error occurred in the conversion
27   (y is NaN, +Inf, or -Inf that have no equivalent in mpf)
28*/
29int
30mpfr_get_f (mpf_ptr x, mpfr_srcptr y, mpfr_rnd_t rnd_mode)
31{
32  int inex;
33  mp_size_t sx, sy;
34  mpfr_prec_t precx, precy;
35  mp_limb_t *xp;
36  int sh;
37
38  if (MPFR_UNLIKELY(MPFR_IS_SINGULAR(y)))
39    {
40      if (MPFR_IS_ZERO(y))
41        {
42          mpf_set_ui (x, 0);
43          return 0;
44        }
45      else if (MPFR_IS_NAN (y))
46        {
47          MPFR_SET_ERANGE ();
48          return 0;
49        }
50      else /* y is plus infinity (resp. minus infinity), set x to the maximum
51              value (resp. the minimum value) in precision PREC(x) */
52        {
53          int i;
54          mp_limb_t *xp;
55
56          MPFR_SET_ERANGE ();
57
58          /* To this day, [mp_exp_t] and mp_size_t are #defined as the same
59             type */
60          EXP (x) = MP_SIZE_T_MAX;
61
62          sx = PREC (x);
63          SIZ (x) = sx;
64          xp = PTR (x);
65          for (i = 0; i < sx; i++)
66            xp[i] = MP_LIMB_T_MAX;
67
68          if (MPFR_IS_POS (y))
69            return -1;
70          else
71            {
72              mpf_neg (x, x);
73              return +1;
74            }
75        }
76    }
77
78  sx = PREC(x); /* number of limbs of the mantissa of x */
79
80  precy = MPFR_PREC(y);
81  precx = (mpfr_prec_t) sx * GMP_NUMB_BITS;
82  sy = MPFR_LIMB_SIZE (y);
83
84  xp = PTR (x);
85
86  /* since mpf numbers are represented in base 2^GMP_NUMB_BITS,
87     we loose -EXP(y) % GMP_NUMB_BITS bits in the most significant limb */
88  sh = MPFR_GET_EXP(y) % GMP_NUMB_BITS;
89  sh = sh <= 0 ? - sh : GMP_NUMB_BITS - sh;
90  MPFR_ASSERTD (sh >= 0);
91  if (precy + sh <= precx) /* we can copy directly */
92    {
93      mp_size_t ds;
94
95      MPFR_ASSERTN (sx >= sy);
96      ds = sx - sy;
97
98      if (sh != 0)
99        {
100          mp_limb_t out;
101          out = mpn_rshift (xp + ds, MPFR_MANT(y), sy, sh);
102          MPFR_ASSERTN (ds > 0 || out == 0);
103          if (ds > 0)
104            xp[--ds] = out;
105        }
106      else
107        MPN_COPY (xp + ds, MPFR_MANT (y), sy);
108      if (ds > 0)
109        MPN_ZERO (xp, ds);
110      EXP(x) = (MPFR_GET_EXP(y) + sh) / GMP_NUMB_BITS;
111      inex = 0;
112    }
113  else /* we have to round to precx - sh bits */
114    {
115      mpfr_t z;
116      mp_size_t sz;
117
118      /* Recall that precx = (mpfr_prec_t) sx * GMP_NUMB_BITS, thus removing
119         sh bits (sh < GMP_NUMB_BITSS) won't reduce the number of limbs. */
120      mpfr_init2 (z, precx - sh);
121      sz = MPFR_LIMB_SIZE (z);
122      MPFR_ASSERTN (sx == sz);
123
124      inex = mpfr_set (z, y, rnd_mode);
125      /* warning, sh may change due to rounding, but then z is a power of two,
126         thus we can safely ignore its last bit which is 0 */
127      sh = MPFR_GET_EXP(z) % GMP_NUMB_BITS;
128      sh = sh <= 0 ? - sh : GMP_NUMB_BITS - sh;
129      MPFR_ASSERTD (sh >= 0);
130      if (sh != 0)
131        {
132          mp_limb_t out;
133          out = mpn_rshift (xp, MPFR_MANT(z), sz, sh);
134          /* If sh hasn't changed, it is the number of the non-significant
135             bits in the lowest limb of z. Therefore out == 0. */
136          MPFR_ASSERTD (out == 0);  (void) out; /* avoid a warning */
137        }
138      else
139        MPN_COPY (xp, MPFR_MANT(z), sz);
140      EXP(x) = (MPFR_GET_EXP(z) + sh) / GMP_NUMB_BITS;
141      mpfr_clear (z);
142    }
143
144  /* set size and sign */
145  SIZ(x) = (MPFR_FROM_SIGN_TO_INT(MPFR_SIGN(y)) < 0) ? -sx : sx;
146
147  return inex;
148}
149