1 /* Exception flags and utilities. Constructors and destructors (debug).
2 
3 Copyright 2001-2020 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 https://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_VAR (mpfr_flags_t, __gmpfr_flags, 0)
MPFR_THREAD_VAR(mpfr_exp_t,__gmpfr_emin,MPFR_EMIN_DEFAULT)26 MPFR_THREAD_VAR (mpfr_exp_t, __gmpfr_emin, MPFR_EMIN_DEFAULT)
27 MPFR_THREAD_VAR (mpfr_exp_t, __gmpfr_emax, MPFR_EMAX_DEFAULT)
28 
29 #undef mpfr_get_emin
30 
31 MPFR_COLD_FUNCTION_ATTR mpfr_exp_t
32 mpfr_get_emin (void)
33 {
34   return __gmpfr_emin;
35 }
36 
37 #undef mpfr_set_emin
38 
39 int
mpfr_set_emin(mpfr_exp_t exponent)40 mpfr_set_emin (mpfr_exp_t exponent)
41 {
42   if (MPFR_LIKELY (exponent >= MPFR_EMIN_MIN && exponent <= MPFR_EMIN_MAX))
43     {
44       __gmpfr_emin = exponent;
45       return 0;
46     }
47   else
48     {
49       return 1;
50     }
51 }
52 
53 MPFR_COLD_FUNCTION_ATTR mpfr_exp_t
mpfr_get_emin_min(void)54 mpfr_get_emin_min (void)
55 {
56   return MPFR_EMIN_MIN;
57 }
58 
59 MPFR_COLD_FUNCTION_ATTR mpfr_exp_t
mpfr_get_emin_max(void)60 mpfr_get_emin_max (void)
61 {
62   return MPFR_EMIN_MAX;
63 }
64 
65 #undef mpfr_get_emax
66 
67 MPFR_COLD_FUNCTION_ATTR mpfr_exp_t
mpfr_get_emax(void)68 mpfr_get_emax (void)
69 {
70   return __gmpfr_emax;
71 }
72 
73 #undef mpfr_set_emax
74 
75 int
mpfr_set_emax(mpfr_exp_t exponent)76 mpfr_set_emax (mpfr_exp_t exponent)
77 {
78   if (MPFR_LIKELY (exponent >= MPFR_EMAX_MIN && exponent <= MPFR_EMAX_MAX))
79     {
80       __gmpfr_emax = exponent;
81       return 0;
82     }
83   else
84     {
85       return 1;
86     }
87 }
88 
89 MPFR_COLD_FUNCTION_ATTR mpfr_exp_t
mpfr_get_emax_min(void)90 mpfr_get_emax_min (void)
91 {
92   return MPFR_EMAX_MIN;
93 }
94 
95 MPFR_COLD_FUNCTION_ATTR mpfr_exp_t
mpfr_get_emax_max(void)96 mpfr_get_emax_max (void)
97 {
98   return MPFR_EMAX_MAX;
99 }
100 
101 
102 #undef mpfr_flags_clear
103 
104 MPFR_COLD_FUNCTION_ATTR void
mpfr_flags_clear(mpfr_flags_t mask)105 mpfr_flags_clear (mpfr_flags_t mask)
106 {
107   __gmpfr_flags &= MPFR_FLAGS_ALL ^ mask;
108 }
109 
110 #undef mpfr_flags_set
111 
112 MPFR_COLD_FUNCTION_ATTR void
mpfr_flags_set(mpfr_flags_t mask)113 mpfr_flags_set (mpfr_flags_t mask)
114 {
115   __gmpfr_flags |= mask;
116 }
117 
118 #undef mpfr_flags_test
119 
120 MPFR_COLD_FUNCTION_ATTR mpfr_flags_t
mpfr_flags_test(mpfr_flags_t mask)121 mpfr_flags_test (mpfr_flags_t mask)
122 {
123   return __gmpfr_flags & mask;
124 }
125 
126 #undef mpfr_flags_save
127 
128 MPFR_COLD_FUNCTION_ATTR mpfr_flags_t
mpfr_flags_save(void)129 mpfr_flags_save (void)
130 {
131   return __gmpfr_flags;
132 }
133 
134 #undef mpfr_flags_restore
135 
136 MPFR_COLD_FUNCTION_ATTR void
mpfr_flags_restore(mpfr_flags_t flags,mpfr_flags_t mask)137 mpfr_flags_restore (mpfr_flags_t flags, mpfr_flags_t mask)
138 {
139   __gmpfr_flags =
140     (__gmpfr_flags & (MPFR_FLAGS_ALL ^ mask)) |
141     (flags & mask);
142 }
143 
144 
145 #undef mpfr_clear_flags
146 
147 void
mpfr_clear_flags(void)148 mpfr_clear_flags (void)
149 {
150   __gmpfr_flags = 0;
151 }
152 
153 #undef mpfr_clear_underflow
154 
155 MPFR_COLD_FUNCTION_ATTR void
mpfr_clear_underflow(void)156 mpfr_clear_underflow (void)
157 {
158   __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_UNDERFLOW;
159 }
160 
161 #undef mpfr_clear_overflow
162 
163 MPFR_COLD_FUNCTION_ATTR void
mpfr_clear_overflow(void)164 mpfr_clear_overflow (void)
165 {
166   __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_OVERFLOW;
167 }
168 
169 #undef mpfr_clear_divby0
170 
171 MPFR_COLD_FUNCTION_ATTR void
mpfr_clear_divby0(void)172 mpfr_clear_divby0 (void)
173 {
174   __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_DIVBY0;
175 }
176 
177 #undef mpfr_clear_nanflag
178 
179 MPFR_COLD_FUNCTION_ATTR void
mpfr_clear_nanflag(void)180 mpfr_clear_nanflag (void)
181 {
182   __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_NAN;
183 }
184 
185 #undef mpfr_clear_inexflag
186 
187 MPFR_COLD_FUNCTION_ATTR void
mpfr_clear_inexflag(void)188 mpfr_clear_inexflag (void)
189 {
190   __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_INEXACT;
191 }
192 
193 #undef mpfr_clear_erangeflag
194 
195 MPFR_COLD_FUNCTION_ATTR void
mpfr_clear_erangeflag(void)196 mpfr_clear_erangeflag (void)
197 {
198   __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_ERANGE;
199 }
200 
201 #undef mpfr_set_underflow
202 
203 MPFR_COLD_FUNCTION_ATTR void
mpfr_set_underflow(void)204 mpfr_set_underflow (void)
205 {
206   __gmpfr_flags |= MPFR_FLAGS_UNDERFLOW;
207 }
208 
209 #undef mpfr_set_overflow
210 
211 MPFR_COLD_FUNCTION_ATTR void
mpfr_set_overflow(void)212 mpfr_set_overflow (void)
213 {
214   __gmpfr_flags |= MPFR_FLAGS_OVERFLOW;
215 }
216 
217 #undef mpfr_set_divby0
218 
219 MPFR_COLD_FUNCTION_ATTR void
mpfr_set_divby0(void)220 mpfr_set_divby0 (void)
221 {
222   __gmpfr_flags |= MPFR_FLAGS_DIVBY0;
223 }
224 
225 #undef mpfr_set_nanflag
226 
227 MPFR_COLD_FUNCTION_ATTR void
mpfr_set_nanflag(void)228 mpfr_set_nanflag (void)
229 {
230   __gmpfr_flags |= MPFR_FLAGS_NAN;
231 }
232 
233 #undef mpfr_set_inexflag
234 
235 MPFR_COLD_FUNCTION_ATTR void
mpfr_set_inexflag(void)236 mpfr_set_inexflag (void)
237 {
238   __gmpfr_flags |= MPFR_FLAGS_INEXACT;
239 }
240 
241 #undef mpfr_set_erangeflag
242 
243 MPFR_COLD_FUNCTION_ATTR void
mpfr_set_erangeflag(void)244 mpfr_set_erangeflag (void)
245 {
246   __gmpfr_flags |= MPFR_FLAGS_ERANGE;
247 }
248 
249 
250 #undef mpfr_check_range
251 
252 /* Note: It is possible that for pure FP numbers, EXP(x) < MPFR_EMIN_MIN,
253    but the caller must make sure that the difference remains small enough
254    to avoid reaching the special exponent values. */
255 int
mpfr_check_range(mpfr_ptr x,int t,mpfr_rnd_t rnd_mode)256 mpfr_check_range (mpfr_ptr x, int t, mpfr_rnd_t rnd_mode)
257 {
258   if (MPFR_LIKELY (! MPFR_IS_SINGULAR (x)))
259     { /* x is a non-zero FP */
260       mpfr_exp_t exp = MPFR_EXP (x);  /* Do not use MPFR_GET_EXP */
261 
262       MPFR_ASSERTD (MPFR_IS_NORMALIZED (x));
263       if (MPFR_UNLIKELY (exp < __gmpfr_emin))
264         {
265           /* The following test is necessary because in the rounding to the
266            * nearest mode, mpfr_underflow always rounds away from 0. In
267            * this rounding mode, we need to round to 0 if:
268            *   _ |x| < 2^(emin-2), or
269            *   _ |x| = 2^(emin-2) and the absolute value of the exact
270            *     result is <= 2^(emin-2).
271            */
272           if (rnd_mode == MPFR_RNDN &&
273               (exp + 1 < __gmpfr_emin ||
274                (mpfr_powerof2_raw(x) &&
275                 (MPFR_IS_NEG(x) ? t <= 0 : t >= 0))))
276             rnd_mode = MPFR_RNDZ;
277           return mpfr_underflow (x, rnd_mode, MPFR_SIGN(x));
278         }
279       if (MPFR_UNLIKELY (exp > __gmpfr_emax))
280         return mpfr_overflow (x, rnd_mode, MPFR_SIGN(x));
281     }
282   else if (MPFR_UNLIKELY (t != 0 && MPFR_IS_INF (x)))
283     {
284       /* We need to do the following because most MPFR functions are
285        * implemented in the following way:
286        *   Ziv's loop:
287        *   | Compute an approximation to the result and an error bound.
288        *   | Possible underflow/overflow detection -> return.
289        *   | If can_round, break (exit the loop).
290        *   | Otherwise, increase the working precision and loop.
291        *   Round the approximation in the target precision.  <== See below
292        *   Restore the flags (that could have been set due to underflows
293        *   or overflows during the internal computations).
294        *   Execute: return mpfr_check_range (...).
295        * The problem is that an overflow could be generated when rounding the
296        * approximation (in general, such an overflow could not be detected
297        * earlier), and the overflow flag is lost when the flags are restored.
298        * This can occur only when the rounding yields an exponent change
299        * and the new exponent is larger than the maximum exponent, so that
300        * an infinity is necessarily obtained.
301        * So, the simplest solution is to detect this overflow case here in
302        * mpfr_check_range, which is easy to do since the rounded result is
303        * necessarily an inexact infinity.
304        */
305       __gmpfr_flags |= MPFR_FLAGS_OVERFLOW;
306     }
307   MPFR_RET (t);  /* propagate inexact ternary value, unlike most functions */
308 }
309 
310 
311 #undef mpfr_underflow_p
312 
313 MPFR_COLD_FUNCTION_ATTR int
mpfr_underflow_p(void)314 mpfr_underflow_p (void)
315 {
316   MPFR_STAT_STATIC_ASSERT (MPFR_FLAGS_UNDERFLOW <= INT_MAX);
317   return __gmpfr_flags & MPFR_FLAGS_UNDERFLOW;
318 }
319 
320 #undef mpfr_overflow_p
321 
322 MPFR_COLD_FUNCTION_ATTR int
mpfr_overflow_p(void)323 mpfr_overflow_p (void)
324 {
325   MPFR_STAT_STATIC_ASSERT (MPFR_FLAGS_OVERFLOW <= INT_MAX);
326   return __gmpfr_flags & MPFR_FLAGS_OVERFLOW;
327 }
328 
329 #undef mpfr_divby0_p
330 
331 MPFR_COLD_FUNCTION_ATTR int
mpfr_divby0_p(void)332 mpfr_divby0_p (void)
333 {
334   MPFR_STAT_STATIC_ASSERT (MPFR_FLAGS_DIVBY0 <= INT_MAX);
335   return __gmpfr_flags & MPFR_FLAGS_DIVBY0;
336 }
337 
338 #undef mpfr_nanflag_p
339 
340 MPFR_COLD_FUNCTION_ATTR int
mpfr_nanflag_p(void)341 mpfr_nanflag_p (void)
342 {
343   MPFR_STAT_STATIC_ASSERT (MPFR_FLAGS_NAN <= INT_MAX);
344   return __gmpfr_flags & MPFR_FLAGS_NAN;
345 }
346 
347 #undef mpfr_inexflag_p
348 
349 MPFR_COLD_FUNCTION_ATTR int
mpfr_inexflag_p(void)350 mpfr_inexflag_p (void)
351 {
352   MPFR_STAT_STATIC_ASSERT (MPFR_FLAGS_INEXACT <= INT_MAX);
353   return __gmpfr_flags & MPFR_FLAGS_INEXACT;
354 }
355 
356 #undef mpfr_erangeflag_p
357 
358 MPFR_COLD_FUNCTION_ATTR int
mpfr_erangeflag_p(void)359 mpfr_erangeflag_p (void)
360 {
361   MPFR_STAT_STATIC_ASSERT (MPFR_FLAGS_ERANGE <= INT_MAX);
362   return __gmpfr_flags & MPFR_FLAGS_ERANGE;
363 }
364 
365 
366 /* #undef mpfr_underflow */
367 
368 /* Note: In the rounding to the nearest mode, mpfr_underflow
369    always rounds away from 0. In this rounding mode, you must call
370    mpfr_underflow with rnd_mode = MPFR_RNDZ if the exact result
371    is <= 2^(emin-2) in absolute value.
372    We chose the default to round away from zero instead of toward zero
373    because rounding away from zero (MPFR_RNDA) wasn't supported at that
374    time (r1910), so that the caller had no way to change rnd_mode to
375    this mode. */
376 
377 MPFR_COLD_FUNCTION_ATTR int
mpfr_underflow(mpfr_ptr x,mpfr_rnd_t rnd_mode,int sign)378 mpfr_underflow (mpfr_ptr x, mpfr_rnd_t rnd_mode, int sign)
379 {
380   int inex;
381 
382   MPFR_LOG_FUNC
383     (("rnd=%d sign=%d", rnd_mode, sign),
384      ("x[%Pu]=%.*Rg", mpfr_get_prec (x), mpfr_log_prec, x));
385 
386   MPFR_ASSERT_SIGN (sign);
387 
388   if (MPFR_IS_LIKE_RNDZ(rnd_mode, sign < 0))
389     {
390       MPFR_SET_ZERO(x);
391       inex = -1;
392     }
393   else
394     {
395       mpfr_setmin (x, __gmpfr_emin);
396       inex = 1;
397     }
398   MPFR_SET_SIGN(x, sign);
399   __gmpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_UNDERFLOW;
400   return sign > 0 ? inex : -inex;
401 }
402 
403 /* #undef mpfr_overflow */
404 
405 MPFR_COLD_FUNCTION_ATTR int
mpfr_overflow(mpfr_ptr x,mpfr_rnd_t rnd_mode,int sign)406 mpfr_overflow (mpfr_ptr x, mpfr_rnd_t rnd_mode, int sign)
407 {
408   int inex;
409 
410   MPFR_LOG_FUNC
411     (("rnd=%d sign=%d", rnd_mode, sign),
412      ("x[%Pu]=%.*Rg", mpfr_get_prec (x), mpfr_log_prec, x));
413 
414   MPFR_ASSERT_SIGN (sign);
415 
416   if (MPFR_IS_LIKE_RNDZ(rnd_mode, sign < 0))
417     {
418       mpfr_setmax (x, __gmpfr_emax);
419       inex = -1;
420     }
421   else
422     {
423       MPFR_SET_INF(x);
424       inex = 1;
425     }
426   MPFR_SET_SIGN(x, sign);
427   __gmpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_OVERFLOW;
428   return sign > 0 ? inex : -inex;
429 }
430 
431 /**************************************************************************/
432 
433 /* Code related to constructors and destructors (for debugging) should
434    be put here. The reason is that such code must be in an object file
435    that will be kept by the linker for symbol resolution, and symbols
436    __gmpfr_emin and __gmpfr_emax from this file will be used by every
437    program calling a MPFR math function (where rounding is involved). */
438 
439 #if defined MPFR_DEBUG_PREDICTION
440 
441 /* Print prediction statistics at the end of a program.
442  *
443  * Code to debug branch prediction, based on Ulrich Drepper's paper
444  * "What Every Programmer Should Know About Memory":
445  *   http://people.freebsd.org/~lstewart/articles/cpumemory.pdf
446  */
447 
448 extern long int __start_predict_data;
449 extern long int __stop_predict_data;
450 extern long int __start_predict_line;
451 extern const char *__start_predict_file;
452 
453 static void __attribute__ ((destructor))
predprint(void)454 predprint (void)
455 {
456   long int *s = &__start_predict_data;
457   long int *e = &__stop_predict_data;
458   long int *sl = &__start_predict_line;
459   const char **sf = &__start_predict_file;
460 
461   while (s < e)
462     {
463       printf("%s:%ld: incorrect=%ld, correct=%ld%s\n",
464              *sf, *sl, s[0], s[1],
465              s[0] > s[1] ? " <==== WARNING" : "");
466       ++sl;
467       ++sf;
468       s += 2;
469     }
470 }
471 
472 #endif
473 
474 #if MPFR_WANT_ASSERT >= 2
475 
476 /* Similar to flags_out in tests/tests.c */
477 
478 void
flags_fout(FILE * stream,mpfr_flags_t flags)479 flags_fout (FILE *stream, mpfr_flags_t flags)
480 {
481   int none = 1;
482 
483   if (flags & MPFR_FLAGS_UNDERFLOW)
484     none = 0, fprintf (stream, " underflow");
485   if (flags & MPFR_FLAGS_OVERFLOW)
486     none = 0, fprintf (stream, " overflow");
487   if (flags & MPFR_FLAGS_NAN)
488     none = 0, fprintf (stream, " nan");
489   if (flags & MPFR_FLAGS_INEXACT)
490     none = 0, fprintf (stream, " inexact");
491   if (flags & MPFR_FLAGS_ERANGE)
492     none = 0, fprintf (stream, " erange");
493   if (none)
494     fprintf (stream, " none");
495   fprintf (stream, " (%u)\n", flags);
496 }
497 
498 #endif
499