xref: /dragonfly/contrib/mpfr/src/exceptions.c (revision 25a2db75)
1 /* Exception flags and utilities.
2 
3 Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
4 Contributed by the AriC and Caramel projects, INRIA.
5 
6 This file is part of the GNU MPFR Library.
7 
8 The GNU MPFR Library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 The GNU MPFR Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16 License for more details.
17 
18 You should have received a copy of the GNU Lesser General Public License
19 along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
20 http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
21 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
22 
23 #include "mpfr-impl.h"
24 
25 unsigned int MPFR_THREAD_ATTR __gmpfr_flags = 0;
26 
27 mpfr_exp_t MPFR_THREAD_ATTR __gmpfr_emin = MPFR_EMIN_DEFAULT;
28 mpfr_exp_t MPFR_THREAD_ATTR __gmpfr_emax = MPFR_EMAX_DEFAULT;
29 
30 #undef mpfr_get_emin
31 
32 mpfr_exp_t
33 mpfr_get_emin (void)
34 {
35   return __gmpfr_emin;
36 }
37 
38 #undef mpfr_set_emin
39 
40 int
41 mpfr_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 
54 mpfr_exp_t
55 mpfr_get_emin_min (void)
56 {
57   return MPFR_EMIN_MIN;
58 }
59 
60 mpfr_exp_t
61 mpfr_get_emin_max (void)
62 {
63   return MPFR_EMIN_MAX;
64 }
65 
66 #undef mpfr_get_emax
67 
68 mpfr_exp_t
69 mpfr_get_emax (void)
70 {
71   return __gmpfr_emax;
72 }
73 
74 #undef mpfr_set_emax
75 
76 int
77 mpfr_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 
90 mpfr_exp_t
91 mpfr_get_emax_min (void)
92 {
93   return MPFR_EMAX_MIN;
94 }
95 mpfr_exp_t
96 mpfr_get_emax_max (void)
97 {
98   return MPFR_EMAX_MAX;
99 }
100 
101 
102 #undef mpfr_clear_flags
103 
104 void
105 mpfr_clear_flags (void)
106 {
107   __gmpfr_flags = 0;
108 }
109 
110 #undef mpfr_clear_underflow
111 
112 void
113 mpfr_clear_underflow (void)
114 {
115   __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_UNDERFLOW;
116 }
117 
118 #undef mpfr_clear_overflow
119 
120 void
121 mpfr_clear_overflow (void)
122 {
123   __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_OVERFLOW;
124 }
125 
126 #undef mpfr_clear_divby0
127 
128 void
129 mpfr_clear_divby0 (void)
130 {
131   __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_DIVBY0;
132 }
133 
134 #undef mpfr_clear_nanflag
135 
136 void
137 mpfr_clear_nanflag (void)
138 {
139   __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_NAN;
140 }
141 
142 #undef mpfr_clear_inexflag
143 
144 void
145 mpfr_clear_inexflag (void)
146 {
147   __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_INEXACT;
148 }
149 
150 #undef mpfr_clear_erangeflag
151 
152 void
153 mpfr_clear_erangeflag (void)
154 {
155   __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_ERANGE;
156 }
157 
158 #undef mpfr_set_underflow
159 
160 void
161 mpfr_set_underflow (void)
162 {
163   __gmpfr_flags |= MPFR_FLAGS_UNDERFLOW;
164 }
165 
166 #undef mpfr_set_overflow
167 
168 void
169 mpfr_set_overflow (void)
170 {
171   __gmpfr_flags |= MPFR_FLAGS_OVERFLOW;
172 }
173 
174 #undef mpfr_set_divby0
175 
176 void
177 mpfr_set_divby0 (void)
178 {
179   __gmpfr_flags |= MPFR_FLAGS_DIVBY0;
180 }
181 
182 #undef mpfr_set_nanflag
183 
184 void
185 mpfr_set_nanflag (void)
186 {
187   __gmpfr_flags |= MPFR_FLAGS_NAN;
188 }
189 
190 #undef mpfr_set_inexflag
191 
192 void
193 mpfr_set_inexflag (void)
194 {
195   __gmpfr_flags |= MPFR_FLAGS_INEXACT;
196 }
197 
198 #undef mpfr_set_erangeflag
199 
200 void
201 mpfr_set_erangeflag (void)
202 {
203   __gmpfr_flags |= MPFR_FLAGS_ERANGE;
204 }
205 
206 
207 #undef mpfr_check_range
208 
209 int
210 mpfr_check_range (mpfr_ptr x, int t, mpfr_rnd_t rnd_mode)
211 {
212   if (MPFR_LIKELY( MPFR_IS_PURE_FP(x)) )
213     { /* x is a non-zero FP */
214       mpfr_exp_t exp = MPFR_EXP (x);  /* Do not use MPFR_GET_EXP */
215       if (MPFR_UNLIKELY( exp < __gmpfr_emin) )
216         {
217           /* The following test is necessary because in the rounding to the
218            * nearest mode, mpfr_underflow always rounds away from 0. In
219            * this rounding mode, we need to round to 0 if:
220            *   _ |x| < 2^(emin-2), or
221            *   _ |x| = 2^(emin-2) and the absolute value of the exact
222            *     result is <= 2^(emin-2).
223            */
224           if (rnd_mode == MPFR_RNDN &&
225               (exp + 1 < __gmpfr_emin ||
226                (mpfr_powerof2_raw(x) &&
227                 (MPFR_IS_NEG(x) ? t <= 0 : t >= 0))))
228             rnd_mode = MPFR_RNDZ;
229           return mpfr_underflow(x, rnd_mode, MPFR_SIGN(x));
230         }
231       if (MPFR_UNLIKELY( exp > __gmpfr_emax) )
232         return mpfr_overflow (x, rnd_mode, MPFR_SIGN(x));
233     }
234   else if (MPFR_UNLIKELY (t != 0 && MPFR_IS_INF (x)))
235     {
236       /* We need to do the following because most MPFR functions are
237        * implemented in the following way:
238        *   Ziv's loop:
239        *   | Compute an approximation to the result and an error bound.
240        *   | Possible underflow/overflow detection -> return.
241        *   | If can_round, break (exit the loop).
242        *   | Otherwise, increase the working precision and loop.
243        *   Round the approximation in the target precision.  <== See below
244        *   Restore the flags (that could have been set due to underflows
245        *   or overflows during the internal computations).
246        *   Execute: return mpfr_check_range (...).
247        * The problem is that an overflow could be generated when rounding the
248        * approximation (in general, such an overflow could not be detected
249        * earlier), and the overflow flag is lost when the flags are restored.
250        * This can occur only when the rounding yields an exponent change
251        * and the new exponent is larger than the maximum exponent, so that
252        * an infinity is necessarily obtained.
253        * So, the simplest solution is to detect this overflow case here in
254        * mpfr_check_range, which is easy to do since the rounded result is
255        * necessarily an inexact infinity.
256        */
257       __gmpfr_flags |= MPFR_FLAGS_OVERFLOW;
258     }
259   MPFR_RET (t);  /* propagate inexact ternary value, unlike most functions */
260 }
261 
262 #undef mpfr_underflow_p
263 
264 int
265 mpfr_underflow_p (void)
266 {
267   return __gmpfr_flags & MPFR_FLAGS_UNDERFLOW;
268 }
269 
270 #undef mpfr_overflow_p
271 
272 int
273 mpfr_overflow_p (void)
274 {
275   return __gmpfr_flags & MPFR_FLAGS_OVERFLOW;
276 }
277 
278 #undef mpfr_divby0_p
279 
280 int
281 mpfr_divby0_p (void)
282 {
283   return __gmpfr_flags & MPFR_FLAGS_DIVBY0;
284 }
285 
286 #undef mpfr_nanflag_p
287 
288 int
289 mpfr_nanflag_p (void)
290 {
291   return __gmpfr_flags & MPFR_FLAGS_NAN;
292 }
293 
294 #undef mpfr_inexflag_p
295 
296 int
297 mpfr_inexflag_p (void)
298 {
299   return __gmpfr_flags & MPFR_FLAGS_INEXACT;
300 }
301 
302 #undef mpfr_erangeflag_p
303 
304 int
305 mpfr_erangeflag_p (void)
306 {
307   return __gmpfr_flags & MPFR_FLAGS_ERANGE;
308 }
309 
310 /* #undef mpfr_underflow */
311 
312 /* Note: In the rounding to the nearest mode, mpfr_underflow
313    always rounds away from 0. In this rounding mode, you must call
314    mpfr_underflow with rnd_mode = MPFR_RNDZ if the exact result
315    is <= 2^(emin-2) in absolute value. */
316 
317 int
318 mpfr_underflow (mpfr_ptr x, mpfr_rnd_t rnd_mode, int sign)
319 {
320   int inex;
321 
322   MPFR_ASSERT_SIGN (sign);
323 
324   if (MPFR_IS_LIKE_RNDZ(rnd_mode, sign < 0))
325     {
326       MPFR_SET_ZERO(x);
327       inex = -1;
328     }
329   else
330     {
331       mpfr_setmin (x, __gmpfr_emin);
332       inex = 1;
333     }
334   MPFR_SET_SIGN(x, sign);
335   __gmpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_UNDERFLOW;
336   return sign > 0 ? inex : -inex;
337 }
338 
339 /* #undef mpfr_overflow */
340 
341 int
342 mpfr_overflow (mpfr_ptr x, mpfr_rnd_t rnd_mode, int sign)
343 {
344   int inex;
345 
346   MPFR_ASSERT_SIGN(sign);
347   if (MPFR_IS_LIKE_RNDZ(rnd_mode, sign < 0))
348     {
349       mpfr_setmax (x, __gmpfr_emax);
350       inex = -1;
351     }
352   else
353     {
354       MPFR_SET_INF(x);
355       inex = 1;
356     }
357   MPFR_SET_SIGN(x,sign);
358   __gmpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_OVERFLOW;
359   return sign > 0 ? inex : -inex;
360 }
361