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