1/* Exception flags and utilities.
2
3Copyright 2001, 2002, 2003, 2004, 2005, 2006, 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
25unsigned int MPFR_THREAD_ATTR __gmpfr_flags = 0;
26
27mpfr_exp_t MPFR_THREAD_ATTR __gmpfr_emin = MPFR_EMIN_DEFAULT;
28mpfr_exp_t MPFR_THREAD_ATTR __gmpfr_emax = MPFR_EMAX_DEFAULT;
29
30#undef mpfr_get_emin
31
32mpfr_exp_t
33mpfr_get_emin (void)
34{
35  return __gmpfr_emin;
36}
37
38#undef mpfr_set_emin
39
40int
41mpfr_set_emin (mpfr_exp_t exponent)
42{
43  if (exponent >= MPFR_EMIN_MIN && exponent <= MPFR_EMIN_MAX)
44    {
45      __gmpfr_emin = exponent;
46      return 0;
47    }
48  else
49    {
50      return 1;
51    }
52}
53
54mpfr_exp_t
55mpfr_get_emin_min (void)
56{
57  return MPFR_EMIN_MIN;
58}
59
60mpfr_exp_t
61mpfr_get_emin_max (void)
62{
63  return MPFR_EMIN_MAX;
64}
65
66#undef mpfr_get_emax
67
68mpfr_exp_t
69mpfr_get_emax (void)
70{
71  return __gmpfr_emax;
72}
73
74#undef mpfr_set_emax
75
76int
77mpfr_set_emax (mpfr_exp_t exponent)
78{
79  if (exponent >= MPFR_EMAX_MIN && exponent <= MPFR_EMAX_MAX)
80    {
81      __gmpfr_emax = exponent;
82      return 0;
83    }
84  else
85    {
86      return 1;
87    }
88}
89
90mpfr_exp_t
91mpfr_get_emax_min (void)
92{
93  return MPFR_EMAX_MIN;
94}
95mpfr_exp_t
96mpfr_get_emax_max (void)
97{
98  return MPFR_EMAX_MAX;
99}
100
101
102#undef mpfr_clear_flags
103
104void
105mpfr_clear_flags (void)
106{
107  __gmpfr_flags = 0;
108}
109
110#undef mpfr_clear_underflow
111
112void
113mpfr_clear_underflow (void)
114{
115  __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_UNDERFLOW;
116}
117
118#undef mpfr_clear_overflow
119
120void
121mpfr_clear_overflow (void)
122{
123  __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_OVERFLOW;
124}
125
126#undef mpfr_clear_nanflag
127
128void
129mpfr_clear_nanflag (void)
130{
131  __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_NAN;
132}
133
134#undef mpfr_clear_inexflag
135
136void
137mpfr_clear_inexflag (void)
138{
139  __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_INEXACT;
140}
141
142#undef mpfr_clear_erangeflag
143
144void
145mpfr_clear_erangeflag (void)
146{
147  __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_ERANGE;
148}
149
150#undef mpfr_clear_underflow
151
152void
153mpfr_set_underflow (void)
154{
155  __gmpfr_flags |= MPFR_FLAGS_UNDERFLOW;
156}
157
158#undef mpfr_clear_overflow
159
160void
161mpfr_set_overflow (void)
162{
163  __gmpfr_flags |= MPFR_FLAGS_OVERFLOW;
164}
165
166#undef mpfr_clear_nanflag
167
168void
169mpfr_set_nanflag (void)
170{
171  __gmpfr_flags |= MPFR_FLAGS_NAN;
172}
173
174#undef mpfr_clear_inexflag
175
176void
177mpfr_set_inexflag (void)
178{
179  __gmpfr_flags |= MPFR_FLAGS_INEXACT;
180}
181
182#undef mpfr_clear_erangeflag
183
184void
185mpfr_set_erangeflag (void)
186{
187  __gmpfr_flags |= MPFR_FLAGS_ERANGE;
188}
189
190
191#undef mpfr_check_range
192
193int
194mpfr_check_range (mpfr_ptr x, int t, mpfr_rnd_t rnd_mode)
195{
196  if (MPFR_LIKELY( MPFR_IS_PURE_FP(x)) )
197    { /* x is a non-zero FP */
198      mpfr_exp_t exp = MPFR_EXP (x);  /* Do not use MPFR_GET_EXP */
199      if (MPFR_UNLIKELY( exp < __gmpfr_emin) )
200        {
201          /* The following test is necessary because in the rounding to the
202           * nearest mode, mpfr_underflow always rounds away from 0. In
203           * this rounding mode, we need to round to 0 if:
204           *   _ |x| < 2^(emin-2), or
205           *   _ |x| = 2^(emin-2) and the absolute value of the exact
206           *     result is <= 2^(emin-2).
207           */
208          if (rnd_mode == MPFR_RNDN &&
209              (exp + 1 < __gmpfr_emin ||
210               (mpfr_powerof2_raw(x) &&
211                (MPFR_IS_NEG(x) ? t <= 0 : t >= 0))))
212            rnd_mode = MPFR_RNDZ;
213          return mpfr_underflow(x, rnd_mode, MPFR_SIGN(x));
214        }
215      if (MPFR_UNLIKELY( exp > __gmpfr_emax) )
216        return mpfr_overflow (x, rnd_mode, MPFR_SIGN(x));
217    }
218  else if (MPFR_UNLIKELY (t != 0 && MPFR_IS_INF (x)))
219    {
220      /* We need to do the following because most MPFR functions are
221       * implemented in the following way:
222       *   Ziv's loop:
223       *   | Compute an approximation to the result and an error bound.
224       *   | Possible underflow/overflow detection -> return.
225       *   | If can_round, break (exit the loop).
226       *   | Otherwise, increase the working precision and loop.
227       *   Round the approximation in the target precision.  <== See below
228       *   Restore the flags (that could have been set due to underflows
229       *   or overflows during the internal computations).
230       *   Execute: return mpfr_check_range (...).
231       * The problem is that an overflow could be generated when rounding the
232       * approximation (in general, such an overflow could not be detected
233       * earlier), and the overflow flag is lost when the flags are restored.
234       * This can occur only when the rounding yields an exponent change
235       * and the new exponent is larger than the maximum exponent, so that
236       * an infinity is necessarily obtained.
237       * So, the simplest solution is to detect this overflow case here in
238       * mpfr_check_range, which is easy to do since the rounded result is
239       * necessarily an inexact infinity.
240       */
241      __gmpfr_flags |= MPFR_FLAGS_OVERFLOW;
242    }
243  MPFR_RET (t);  /* propagate inexact ternary value, unlike most functions */
244}
245
246#undef mpfr_underflow_p
247
248int
249mpfr_underflow_p (void)
250{
251  return __gmpfr_flags & MPFR_FLAGS_UNDERFLOW;
252}
253
254#undef mpfr_overflow_p
255
256int
257mpfr_overflow_p (void)
258{
259  return __gmpfr_flags & MPFR_FLAGS_OVERFLOW;
260}
261
262#undef mpfr_nanflag_p
263
264int
265mpfr_nanflag_p (void)
266{
267  return __gmpfr_flags & MPFR_FLAGS_NAN;
268}
269
270#undef mpfr_inexflag_p
271
272int
273mpfr_inexflag_p (void)
274{
275  return __gmpfr_flags & MPFR_FLAGS_INEXACT;
276}
277
278#undef mpfr_erangeflag_p
279
280int
281mpfr_erangeflag_p (void)
282{
283  return __gmpfr_flags & MPFR_FLAGS_ERANGE;
284}
285
286/* #undef mpfr_underflow */
287
288/* Note: In the rounding to the nearest mode, mpfr_underflow
289   always rounds away from 0. In this rounding mode, you must call
290   mpfr_underflow with rnd_mode = MPFR_RNDZ if the exact result
291   is <= 2^(emin-2) in absolute value. */
292
293int
294mpfr_underflow (mpfr_ptr x, mpfr_rnd_t rnd_mode, int sign)
295{
296  int inex;
297
298  MPFR_ASSERT_SIGN (sign);
299
300  if (MPFR_IS_LIKE_RNDZ(rnd_mode, sign < 0))
301    {
302      MPFR_SET_ZERO(x);
303      inex = -1;
304    }
305  else
306    {
307      mpfr_setmin (x, __gmpfr_emin);
308      inex = 1;
309    }
310  MPFR_SET_SIGN(x, sign);
311  __gmpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_UNDERFLOW;
312  return sign > 0 ? inex : -inex;
313}
314
315/* #undef mpfr_overflow */
316
317int
318mpfr_overflow (mpfr_ptr x, mpfr_rnd_t rnd_mode, int sign)
319{
320  int inex;
321
322  MPFR_ASSERT_SIGN(sign);
323  if (MPFR_IS_LIKE_RNDZ(rnd_mode, sign < 0))
324    {
325      mpfr_setmax (x, __gmpfr_emax);
326      inex = -1;
327    }
328  else
329    {
330      MPFR_SET_INF(x);
331      inex = 1;
332    }
333  MPFR_SET_SIGN(x,sign);
334  __gmpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_OVERFLOW;
335  return sign > 0 ? inex : -inex;
336}
337