1/* mpfr_modf -- Integral and fractional part.
2
3Copyright 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
4Contributed by the Arenaire and Cacao 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#define INEXPOS(y) ((y) == 0 ? 0 : (((y) > 0) ? 1 : 2))
26#define INEX(y,z) (INEXPOS(y) | (INEXPOS(z) << 2))
27
28/* Set iop to the integral part of op and fop to its fractional part */
29int
30mpfr_modf (mpfr_ptr iop, mpfr_ptr fop, mpfr_srcptr op, mpfr_rnd_t rnd_mode)
31{
32  mpfr_exp_t ope;
33  mpfr_prec_t opq;
34  int inexi, inexf;
35
36  MPFR_LOG_FUNC (("op[%#R]=%R rnd=%d", op, op, rnd_mode),
37                 ("iop[%#R]=%R fop[%#R]=%R", iop, iop, fop, fop));
38
39  MPFR_ASSERTN (iop != fop);
40
41  if ( MPFR_UNLIKELY (MPFR_IS_SINGULAR (op)) )
42    {
43      if (MPFR_IS_NAN (op))
44        {
45          MPFR_SET_NAN (iop);
46          MPFR_SET_NAN (fop);
47          MPFR_RET_NAN;
48        }
49      MPFR_SET_SAME_SIGN (iop, op);
50      MPFR_SET_SAME_SIGN (fop, op);
51      if (MPFR_IS_INF (op))
52        {
53          MPFR_SET_INF (iop);
54          MPFR_SET_ZERO (fop);
55          MPFR_RET (0);
56        }
57      else /* op is zero */
58        {
59          MPFR_ASSERTD (MPFR_IS_ZERO (op));
60          MPFR_SET_ZERO (iop);
61          MPFR_SET_ZERO (fop);
62          MPFR_RET (0);
63        }
64    }
65
66  ope = MPFR_GET_EXP (op);
67  opq = MPFR_PREC (op);
68
69  if (ope <= 0)   /* 0 < |op| < 1 */
70    {
71      inexf = (fop != op) ? mpfr_set (fop, op, rnd_mode) : 0;
72      MPFR_SET_SAME_SIGN (iop, op);
73      MPFR_SET_ZERO (iop);
74      MPFR_RET (INEX(0, inexf));
75    }
76  else if (ope >= opq) /* op has no fractional part */
77    {
78      inexi = (iop != op) ? mpfr_set (iop, op, rnd_mode) : 0;
79      MPFR_SET_SAME_SIGN (fop, op);
80      MPFR_SET_ZERO (fop);
81      MPFR_RET (INEX(inexi, 0));
82    }
83  else /* op has both integral and fractional parts */
84    {
85      if (iop != op)
86        {
87          inexi = mpfr_rint_trunc (iop, op, rnd_mode);
88          inexf = mpfr_frac (fop, op, rnd_mode);
89        }
90      else
91        {
92          MPFR_ASSERTN (fop != op);
93          inexf = mpfr_frac (fop, op, rnd_mode);
94          inexi = mpfr_rint_trunc (iop, op, rnd_mode);
95        }
96      MPFR_RET (INEX(inexi, inexf));
97    }
98}
99