1 /* Exception flags and utilities. Constructors and destructors (debug).
2
3 Copyright 2001-2023 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 /* This function does not have logging messages. As it is also partly
256 implemented as a macro, if messages are added in the future, the macro
257 may need to be disabled when logging is enabled. */
258 int
mpfr_check_range(mpfr_ptr x,int t,mpfr_rnd_t rnd_mode)259 mpfr_check_range (mpfr_ptr x, int t, mpfr_rnd_t rnd_mode)
260 {
261 if (MPFR_LIKELY (! MPFR_IS_SINGULAR (x)))
262 { /* x is a non-zero FP */
263 mpfr_exp_t exp = MPFR_EXP (x); /* Do not use MPFR_GET_EXP */
264
265 MPFR_ASSERTD (MPFR_IS_NORMALIZED (x));
266 if (MPFR_UNLIKELY (exp < __gmpfr_emin))
267 {
268 /* The following test is necessary because in the rounding to the
269 * nearest mode, mpfr_underflow always rounds away from 0. In
270 * this rounding mode, we need to round to 0 if:
271 * _ |x| < 2^(emin-2), or
272 * _ |x| = 2^(emin-2) and the absolute value of the exact
273 * result is <= 2^(emin-2).
274 */
275 if (rnd_mode == MPFR_RNDN &&
276 (exp + 1 < __gmpfr_emin ||
277 (mpfr_powerof2_raw(x) &&
278 (MPFR_IS_NEG(x) ? t <= 0 : t >= 0))))
279 rnd_mode = MPFR_RNDZ;
280 return mpfr_underflow (x, rnd_mode, MPFR_SIGN(x));
281 }
282 if (MPFR_UNLIKELY (exp > __gmpfr_emax))
283 return mpfr_overflow (x, rnd_mode, MPFR_SIGN(x));
284 }
285 else if (MPFR_UNLIKELY (t != 0 && MPFR_IS_INF (x)))
286 {
287 /* We need to do the following because most MPFR functions are
288 * implemented in the following way:
289 * Ziv's loop:
290 * | Compute an approximation to the result and an error bound.
291 * | Possible underflow/overflow detection -> return.
292 * | If can_round, break (exit the loop).
293 * | Otherwise, increase the working precision and loop.
294 * Round the approximation in the target precision. <== See below
295 * Restore the flags (that could have been set due to underflows
296 * or overflows during the internal computations).
297 * Execute: return mpfr_check_range (...).
298 * The problem is that an overflow could be generated when rounding the
299 * approximation (in general, such an overflow could not be detected
300 * earlier), and the overflow flag is lost when the flags are restored.
301 * This can occur only when the rounding yields an exponent change
302 * and the new exponent is larger than the maximum exponent, so that
303 * an infinity is necessarily obtained.
304 * So, the simplest solution is to detect this overflow case here in
305 * mpfr_check_range, which is easy to do since the rounded result is
306 * necessarily an inexact infinity.
307 */
308 __gmpfr_flags |= MPFR_FLAGS_OVERFLOW;
309 }
310 MPFR_RET (t); /* propagate inexact ternary value, unlike most functions */
311 }
312
313
314 #undef mpfr_underflow_p
315
316 MPFR_COLD_FUNCTION_ATTR int
mpfr_underflow_p(void)317 mpfr_underflow_p (void)
318 {
319 MPFR_STAT_STATIC_ASSERT (MPFR_FLAGS_UNDERFLOW <= INT_MAX);
320 return __gmpfr_flags & MPFR_FLAGS_UNDERFLOW;
321 }
322
323 #undef mpfr_overflow_p
324
325 MPFR_COLD_FUNCTION_ATTR int
mpfr_overflow_p(void)326 mpfr_overflow_p (void)
327 {
328 MPFR_STAT_STATIC_ASSERT (MPFR_FLAGS_OVERFLOW <= INT_MAX);
329 return __gmpfr_flags & MPFR_FLAGS_OVERFLOW;
330 }
331
332 #undef mpfr_divby0_p
333
334 MPFR_COLD_FUNCTION_ATTR int
mpfr_divby0_p(void)335 mpfr_divby0_p (void)
336 {
337 MPFR_STAT_STATIC_ASSERT (MPFR_FLAGS_DIVBY0 <= INT_MAX);
338 return __gmpfr_flags & MPFR_FLAGS_DIVBY0;
339 }
340
341 #undef mpfr_nanflag_p
342
343 MPFR_COLD_FUNCTION_ATTR int
mpfr_nanflag_p(void)344 mpfr_nanflag_p (void)
345 {
346 MPFR_STAT_STATIC_ASSERT (MPFR_FLAGS_NAN <= INT_MAX);
347 return __gmpfr_flags & MPFR_FLAGS_NAN;
348 }
349
350 #undef mpfr_inexflag_p
351
352 MPFR_COLD_FUNCTION_ATTR int
mpfr_inexflag_p(void)353 mpfr_inexflag_p (void)
354 {
355 MPFR_STAT_STATIC_ASSERT (MPFR_FLAGS_INEXACT <= INT_MAX);
356 return __gmpfr_flags & MPFR_FLAGS_INEXACT;
357 }
358
359 #undef mpfr_erangeflag_p
360
361 MPFR_COLD_FUNCTION_ATTR int
mpfr_erangeflag_p(void)362 mpfr_erangeflag_p (void)
363 {
364 MPFR_STAT_STATIC_ASSERT (MPFR_FLAGS_ERANGE <= INT_MAX);
365 return __gmpfr_flags & MPFR_FLAGS_ERANGE;
366 }
367
368
369 /* #undef mpfr_underflow */
370
371 /* Note: In the rounding to the nearest mode, mpfr_underflow
372 always rounds away from 0. In this rounding mode, you must call
373 mpfr_underflow with rnd_mode = MPFR_RNDZ if the exact result
374 is <= 2^(emin-2) in absolute value.
375 We chose the default to round away from zero instead of toward zero
376 because rounding away from zero (MPFR_RNDA) wasn't supported at that
377 time (r1910), so that the caller had no way to change rnd_mode to
378 this mode. */
379
380 MPFR_COLD_FUNCTION_ATTR int
mpfr_underflow(mpfr_ptr x,mpfr_rnd_t rnd_mode,int sign)381 mpfr_underflow (mpfr_ptr x, mpfr_rnd_t rnd_mode, int sign)
382 {
383 int inex;
384
385 MPFR_LOG_FUNC
386 (("rnd=%d sign=%d", rnd_mode, sign),
387 ("x[%Pd]=%.*Rg", mpfr_get_prec (x), mpfr_log_prec, x));
388
389 MPFR_ASSERT_SIGN (sign);
390
391 if (MPFR_IS_LIKE_RNDZ(rnd_mode, sign < 0))
392 {
393 MPFR_SET_ZERO(x);
394 inex = -1;
395 }
396 else
397 {
398 mpfr_setmin (x, __gmpfr_emin);
399 inex = 1;
400 }
401 MPFR_SET_SIGN(x, sign);
402 __gmpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_UNDERFLOW;
403 return sign > 0 ? inex : -inex;
404 }
405
406 /* #undef mpfr_overflow */
407
408 MPFR_COLD_FUNCTION_ATTR int
mpfr_overflow(mpfr_ptr x,mpfr_rnd_t rnd_mode,int sign)409 mpfr_overflow (mpfr_ptr x, mpfr_rnd_t rnd_mode, int sign)
410 {
411 int inex;
412
413 MPFR_LOG_FUNC
414 (("rnd=%d sign=%d", rnd_mode, sign),
415 ("x[%Pd]=%.*Rg", mpfr_get_prec (x), mpfr_log_prec, x));
416
417 MPFR_ASSERT_SIGN (sign);
418
419 if (MPFR_IS_LIKE_RNDZ(rnd_mode, sign < 0))
420 {
421 mpfr_setmax (x, __gmpfr_emax);
422 inex = -1;
423 }
424 else
425 {
426 MPFR_SET_INF(x);
427 inex = 1;
428 }
429 MPFR_SET_SIGN(x, sign);
430 __gmpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_OVERFLOW;
431 return sign > 0 ? inex : -inex;
432 }
433
434 /**************************************************************************/
435
436 /* Code related to constructors and destructors (for debugging) should
437 be put here. The reason is that such code must be in an object file
438 that will be kept by the linker for symbol resolution, and symbols
439 __gmpfr_emin and __gmpfr_emax from this file will be used by every
440 program calling a MPFR math function (where rounding is involved). */
441
442 #if defined MPFR_DEBUG_PREDICTION
443
444 /* Print prediction statistics at the end of a program.
445 *
446 * Code to debug branch prediction, based on Ulrich Drepper's paper
447 * "What Every Programmer Should Know About Memory":
448 * https://people.freebsd.org/~lstewart/articles/cpumemory.pdf
449 */
450
451 extern long int __start_predict_data;
452 extern long int __stop_predict_data;
453 extern long int __start_predict_line;
454 extern const char *__start_predict_file;
455
456 static void __attribute__ ((destructor))
predprint(void)457 predprint (void)
458 {
459 long int *s = &__start_predict_data;
460 long int *e = &__stop_predict_data;
461 long int *sl = &__start_predict_line;
462 const char **sf = &__start_predict_file;
463
464 while (s < e)
465 {
466 printf("%s:%ld: incorrect=%ld, correct=%ld%s\n",
467 *sf, *sl, s[0], s[1],
468 s[0] > s[1] ? " <==== WARNING" : "");
469 ++sl;
470 ++sf;
471 s += 2;
472 }
473 }
474
475 #endif
476
477 #if MPFR_WANT_ASSERT >= 2
478
479 /* Similar to flags_out in tests/tests.c */
480
481 void
flags_fout(FILE * stream,mpfr_flags_t flags)482 flags_fout (FILE *stream, mpfr_flags_t flags)
483 {
484 int none = 1;
485
486 if (flags & MPFR_FLAGS_UNDERFLOW)
487 none = 0, fprintf (stream, " underflow");
488 if (flags & MPFR_FLAGS_OVERFLOW)
489 none = 0, fprintf (stream, " overflow");
490 if (flags & MPFR_FLAGS_NAN)
491 none = 0, fprintf (stream, " nan");
492 if (flags & MPFR_FLAGS_INEXACT)
493 none = 0, fprintf (stream, " inexact");
494 if (flags & MPFR_FLAGS_ERANGE)
495 none = 0, fprintf (stream, " erange");
496 if (none)
497 fprintf (stream, " none");
498 fprintf (stream, " (%u)\n", flags);
499 }
500
501 #endif
502