1/* mpfr_nextabove, mpfr_nextbelow, mpfr_nexttoward -- next representable
2floating-point number
3
4Copyright 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
5Contributed by the AriC and Caramel projects, INRIA.
6
7This file is part of the GNU MPFR Library.
8
9The GNU MPFR Library is free software; you can redistribute it and/or modify
10it under the terms of the GNU Lesser General Public License as published by
11the Free Software Foundation; either version 3 of the License, or (at your
12option) any later version.
13
14The GNU MPFR Library is distributed in the hope that it will be useful, but
15WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17License for more details.
18
19You should have received a copy of the GNU Lesser General Public License
20along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
21http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
2251 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
23
24#include "mpfr-impl.h"
25
26void
27mpfr_nexttozero (mpfr_ptr x)
28{
29  if (MPFR_UNLIKELY(MPFR_IS_INF(x)))
30    {
31      mpfr_setmax (x, __gmpfr_emax);
32      return;
33    }
34  else if (MPFR_UNLIKELY( MPFR_IS_ZERO(x) ))
35    {
36      MPFR_CHANGE_SIGN(x);
37      mpfr_setmin (x, __gmpfr_emin);
38    }
39  else
40    {
41      mp_size_t xn;
42      int sh;
43      mp_limb_t *xp;
44
45      xn = MPFR_LIMB_SIZE (x);
46      MPFR_UNSIGNED_MINUS_MODULO (sh, MPFR_PREC(x));
47      xp = MPFR_MANT(x);
48      mpn_sub_1 (xp, xp, xn, MPFR_LIMB_ONE << sh);
49      if (MPFR_UNLIKELY( MPFR_LIMB_MSB(xp[xn-1]) == 0) )
50        { /* was an exact power of two: not normalized any more */
51          mpfr_exp_t exp = MPFR_EXP (x);
52          if (MPFR_UNLIKELY(exp == __gmpfr_emin))
53            MPFR_SET_ZERO(x);
54          else
55            {
56              mp_size_t i;
57              MPFR_SET_EXP (x, exp - 1);
58              xp[0] = MP_LIMB_T_MAX << sh;
59              for (i = 1; i < xn; i++)
60                xp[i] = MP_LIMB_T_MAX;
61            }
62        }
63    }
64}
65
66void
67mpfr_nexttoinf (mpfr_ptr x)
68{
69  if (MPFR_UNLIKELY(MPFR_IS_INF(x)))
70    return;
71  else if (MPFR_UNLIKELY(MPFR_IS_ZERO(x)))
72    mpfr_setmin (x, __gmpfr_emin);
73  else
74    {
75      mp_size_t xn;
76      int sh;
77      mp_limb_t *xp;
78
79      xn = MPFR_LIMB_SIZE (x);
80      MPFR_UNSIGNED_MINUS_MODULO (sh, MPFR_PREC(x));
81      xp = MPFR_MANT(x);
82      if (MPFR_UNLIKELY( mpn_add_1 (xp, xp, xn, MPFR_LIMB_ONE << sh)) )
83        /* got 1.0000... */
84        {
85          mpfr_exp_t exp = MPFR_EXP (x);
86          if (MPFR_UNLIKELY(exp == __gmpfr_emax))
87            MPFR_SET_INF(x);
88          else
89            {
90              MPFR_SET_EXP (x, exp + 1);
91              xp[xn-1] = MPFR_LIMB_HIGHBIT;
92            }
93        }
94    }
95}
96
97void
98mpfr_nextabove (mpfr_ptr x)
99{
100  if (MPFR_UNLIKELY(MPFR_IS_NAN(x)))
101    {
102      __gmpfr_flags |= MPFR_FLAGS_NAN;
103      return;
104    }
105  if (MPFR_IS_NEG(x))
106    mpfr_nexttozero (x);
107  else
108    mpfr_nexttoinf (x);
109}
110
111void
112mpfr_nextbelow (mpfr_ptr x)
113{
114  if (MPFR_UNLIKELY(MPFR_IS_NAN(x)))
115    {
116      __gmpfr_flags |= MPFR_FLAGS_NAN;
117      return;
118    }
119
120  if (MPFR_IS_NEG(x))
121    mpfr_nexttoinf (x);
122  else
123    mpfr_nexttozero (x);
124}
125
126void
127mpfr_nexttoward (mpfr_ptr x, mpfr_srcptr y)
128{
129  int s;
130
131  if (MPFR_UNLIKELY(MPFR_IS_NAN(x)))
132    {
133      __gmpfr_flags |= MPFR_FLAGS_NAN;
134      return;
135    }
136  else if (MPFR_UNLIKELY(MPFR_IS_NAN(x) || MPFR_IS_NAN(y)))
137    {
138      MPFR_SET_NAN(x);
139      __gmpfr_flags |= MPFR_FLAGS_NAN;
140      return;
141    }
142
143  s = mpfr_cmp (x, y);
144  if (s == 0)
145    return;
146  else if (s < 0)
147    mpfr_nextabove (x);
148  else
149    mpfr_nextbelow (x);
150}
151