xref: /dflybsd-src/contrib/mpfr/src/exceptions.c (revision 2786097444a0124b5d33763854de247e230c6629)
14a238c70SJohn Marino /* Exception flags and utilities.
24a238c70SJohn Marino 
3*ab6d115fSJohn Marino Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
4*ab6d115fSJohn Marino Contributed by the AriC and Caramel projects, INRIA.
54a238c70SJohn Marino 
64a238c70SJohn Marino This file is part of the GNU MPFR Library.
74a238c70SJohn Marino 
84a238c70SJohn Marino The GNU MPFR Library is free software; you can redistribute it and/or modify
94a238c70SJohn Marino it under the terms of the GNU Lesser General Public License as published by
104a238c70SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your
114a238c70SJohn Marino option) any later version.
124a238c70SJohn Marino 
134a238c70SJohn Marino The GNU MPFR Library is distributed in the hope that it will be useful, but
144a238c70SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
154a238c70SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
164a238c70SJohn Marino License for more details.
174a238c70SJohn Marino 
184a238c70SJohn Marino You should have received a copy of the GNU Lesser General Public License
194a238c70SJohn Marino along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
204a238c70SJohn Marino http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
214a238c70SJohn Marino 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
224a238c70SJohn Marino 
234a238c70SJohn Marino #include "mpfr-impl.h"
244a238c70SJohn Marino 
254a238c70SJohn Marino unsigned int MPFR_THREAD_ATTR __gmpfr_flags = 0;
264a238c70SJohn Marino 
274a238c70SJohn Marino mpfr_exp_t MPFR_THREAD_ATTR __gmpfr_emin = MPFR_EMIN_DEFAULT;
284a238c70SJohn Marino mpfr_exp_t MPFR_THREAD_ATTR __gmpfr_emax = MPFR_EMAX_DEFAULT;
294a238c70SJohn Marino 
304a238c70SJohn Marino #undef mpfr_get_emin
314a238c70SJohn Marino 
324a238c70SJohn Marino mpfr_exp_t
mpfr_get_emin(void)334a238c70SJohn Marino mpfr_get_emin (void)
344a238c70SJohn Marino {
354a238c70SJohn Marino   return __gmpfr_emin;
364a238c70SJohn Marino }
374a238c70SJohn Marino 
384a238c70SJohn Marino #undef mpfr_set_emin
394a238c70SJohn Marino 
404a238c70SJohn Marino int
mpfr_set_emin(mpfr_exp_t exponent)414a238c70SJohn Marino mpfr_set_emin (mpfr_exp_t exponent)
424a238c70SJohn Marino {
434a238c70SJohn Marino   if (exponent >= MPFR_EMIN_MIN && exponent <= MPFR_EMIN_MAX)
444a238c70SJohn Marino     {
454a238c70SJohn Marino       __gmpfr_emin = exponent;
464a238c70SJohn Marino       return 0;
474a238c70SJohn Marino     }
484a238c70SJohn Marino   else
494a238c70SJohn Marino     {
504a238c70SJohn Marino       return 1;
514a238c70SJohn Marino     }
524a238c70SJohn Marino }
534a238c70SJohn Marino 
544a238c70SJohn Marino mpfr_exp_t
mpfr_get_emin_min(void)554a238c70SJohn Marino mpfr_get_emin_min (void)
564a238c70SJohn Marino {
574a238c70SJohn Marino   return MPFR_EMIN_MIN;
584a238c70SJohn Marino }
594a238c70SJohn Marino 
604a238c70SJohn Marino mpfr_exp_t
mpfr_get_emin_max(void)614a238c70SJohn Marino mpfr_get_emin_max (void)
624a238c70SJohn Marino {
634a238c70SJohn Marino   return MPFR_EMIN_MAX;
644a238c70SJohn Marino }
654a238c70SJohn Marino 
664a238c70SJohn Marino #undef mpfr_get_emax
674a238c70SJohn Marino 
684a238c70SJohn Marino mpfr_exp_t
mpfr_get_emax(void)694a238c70SJohn Marino mpfr_get_emax (void)
704a238c70SJohn Marino {
714a238c70SJohn Marino   return __gmpfr_emax;
724a238c70SJohn Marino }
734a238c70SJohn Marino 
744a238c70SJohn Marino #undef mpfr_set_emax
754a238c70SJohn Marino 
764a238c70SJohn Marino int
mpfr_set_emax(mpfr_exp_t exponent)774a238c70SJohn Marino mpfr_set_emax (mpfr_exp_t exponent)
784a238c70SJohn Marino {
794a238c70SJohn Marino   if (exponent >= MPFR_EMAX_MIN && exponent <= MPFR_EMAX_MAX)
804a238c70SJohn Marino     {
814a238c70SJohn Marino       __gmpfr_emax = exponent;
824a238c70SJohn Marino       return 0;
834a238c70SJohn Marino     }
844a238c70SJohn Marino   else
854a238c70SJohn Marino     {
864a238c70SJohn Marino       return 1;
874a238c70SJohn Marino     }
884a238c70SJohn Marino }
894a238c70SJohn Marino 
904a238c70SJohn Marino mpfr_exp_t
mpfr_get_emax_min(void)914a238c70SJohn Marino mpfr_get_emax_min (void)
924a238c70SJohn Marino {
934a238c70SJohn Marino   return MPFR_EMAX_MIN;
944a238c70SJohn Marino }
954a238c70SJohn Marino mpfr_exp_t
mpfr_get_emax_max(void)964a238c70SJohn Marino mpfr_get_emax_max (void)
974a238c70SJohn Marino {
984a238c70SJohn Marino   return MPFR_EMAX_MAX;
994a238c70SJohn Marino }
1004a238c70SJohn Marino 
1014a238c70SJohn Marino 
1024a238c70SJohn Marino #undef mpfr_clear_flags
1034a238c70SJohn Marino 
1044a238c70SJohn Marino void
mpfr_clear_flags(void)1054a238c70SJohn Marino mpfr_clear_flags (void)
1064a238c70SJohn Marino {
1074a238c70SJohn Marino   __gmpfr_flags = 0;
1084a238c70SJohn Marino }
1094a238c70SJohn Marino 
1104a238c70SJohn Marino #undef mpfr_clear_underflow
1114a238c70SJohn Marino 
1124a238c70SJohn Marino void
mpfr_clear_underflow(void)1134a238c70SJohn Marino mpfr_clear_underflow (void)
1144a238c70SJohn Marino {
1154a238c70SJohn Marino   __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_UNDERFLOW;
1164a238c70SJohn Marino }
1174a238c70SJohn Marino 
1184a238c70SJohn Marino #undef mpfr_clear_overflow
1194a238c70SJohn Marino 
1204a238c70SJohn Marino void
mpfr_clear_overflow(void)1214a238c70SJohn Marino mpfr_clear_overflow (void)
1224a238c70SJohn Marino {
1234a238c70SJohn Marino   __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_OVERFLOW;
1244a238c70SJohn Marino }
1254a238c70SJohn Marino 
1264a238c70SJohn Marino #undef mpfr_clear_divby0
1274a238c70SJohn Marino 
1284a238c70SJohn Marino void
mpfr_clear_divby0(void)1294a238c70SJohn Marino mpfr_clear_divby0 (void)
1304a238c70SJohn Marino {
1314a238c70SJohn Marino   __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_DIVBY0;
1324a238c70SJohn Marino }
1334a238c70SJohn Marino 
1344a238c70SJohn Marino #undef mpfr_clear_nanflag
1354a238c70SJohn Marino 
1364a238c70SJohn Marino void
mpfr_clear_nanflag(void)1374a238c70SJohn Marino mpfr_clear_nanflag (void)
1384a238c70SJohn Marino {
1394a238c70SJohn Marino   __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_NAN;
1404a238c70SJohn Marino }
1414a238c70SJohn Marino 
1424a238c70SJohn Marino #undef mpfr_clear_inexflag
1434a238c70SJohn Marino 
1444a238c70SJohn Marino void
mpfr_clear_inexflag(void)1454a238c70SJohn Marino mpfr_clear_inexflag (void)
1464a238c70SJohn Marino {
1474a238c70SJohn Marino   __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_INEXACT;
1484a238c70SJohn Marino }
1494a238c70SJohn Marino 
1504a238c70SJohn Marino #undef mpfr_clear_erangeflag
1514a238c70SJohn Marino 
1524a238c70SJohn Marino void
mpfr_clear_erangeflag(void)1534a238c70SJohn Marino mpfr_clear_erangeflag (void)
1544a238c70SJohn Marino {
1554a238c70SJohn Marino   __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_ERANGE;
1564a238c70SJohn Marino }
1574a238c70SJohn Marino 
1584a238c70SJohn Marino #undef mpfr_set_underflow
1594a238c70SJohn Marino 
1604a238c70SJohn Marino void
mpfr_set_underflow(void)1614a238c70SJohn Marino mpfr_set_underflow (void)
1624a238c70SJohn Marino {
1634a238c70SJohn Marino   __gmpfr_flags |= MPFR_FLAGS_UNDERFLOW;
1644a238c70SJohn Marino }
1654a238c70SJohn Marino 
1664a238c70SJohn Marino #undef mpfr_set_overflow
1674a238c70SJohn Marino 
1684a238c70SJohn Marino void
mpfr_set_overflow(void)1694a238c70SJohn Marino mpfr_set_overflow (void)
1704a238c70SJohn Marino {
1714a238c70SJohn Marino   __gmpfr_flags |= MPFR_FLAGS_OVERFLOW;
1724a238c70SJohn Marino }
1734a238c70SJohn Marino 
1744a238c70SJohn Marino #undef mpfr_set_divby0
1754a238c70SJohn Marino 
1764a238c70SJohn Marino void
mpfr_set_divby0(void)1774a238c70SJohn Marino mpfr_set_divby0 (void)
1784a238c70SJohn Marino {
1794a238c70SJohn Marino   __gmpfr_flags |= MPFR_FLAGS_DIVBY0;
1804a238c70SJohn Marino }
1814a238c70SJohn Marino 
1824a238c70SJohn Marino #undef mpfr_set_nanflag
1834a238c70SJohn Marino 
1844a238c70SJohn Marino void
mpfr_set_nanflag(void)1854a238c70SJohn Marino mpfr_set_nanflag (void)
1864a238c70SJohn Marino {
1874a238c70SJohn Marino   __gmpfr_flags |= MPFR_FLAGS_NAN;
1884a238c70SJohn Marino }
1894a238c70SJohn Marino 
1904a238c70SJohn Marino #undef mpfr_set_inexflag
1914a238c70SJohn Marino 
1924a238c70SJohn Marino void
mpfr_set_inexflag(void)1934a238c70SJohn Marino mpfr_set_inexflag (void)
1944a238c70SJohn Marino {
1954a238c70SJohn Marino   __gmpfr_flags |= MPFR_FLAGS_INEXACT;
1964a238c70SJohn Marino }
1974a238c70SJohn Marino 
1984a238c70SJohn Marino #undef mpfr_set_erangeflag
1994a238c70SJohn Marino 
2004a238c70SJohn Marino void
mpfr_set_erangeflag(void)2014a238c70SJohn Marino mpfr_set_erangeflag (void)
2024a238c70SJohn Marino {
2034a238c70SJohn Marino   __gmpfr_flags |= MPFR_FLAGS_ERANGE;
2044a238c70SJohn Marino }
2054a238c70SJohn Marino 
2064a238c70SJohn Marino 
2074a238c70SJohn Marino #undef mpfr_check_range
2084a238c70SJohn Marino 
2094a238c70SJohn Marino int
mpfr_check_range(mpfr_ptr x,int t,mpfr_rnd_t rnd_mode)2104a238c70SJohn Marino mpfr_check_range (mpfr_ptr x, int t, mpfr_rnd_t rnd_mode)
2114a238c70SJohn Marino {
2124a238c70SJohn Marino   if (MPFR_LIKELY( MPFR_IS_PURE_FP(x)) )
2134a238c70SJohn Marino     { /* x is a non-zero FP */
2144a238c70SJohn Marino       mpfr_exp_t exp = MPFR_EXP (x);  /* Do not use MPFR_GET_EXP */
2154a238c70SJohn Marino       if (MPFR_UNLIKELY( exp < __gmpfr_emin) )
2164a238c70SJohn Marino         {
2174a238c70SJohn Marino           /* The following test is necessary because in the rounding to the
2184a238c70SJohn Marino            * nearest mode, mpfr_underflow always rounds away from 0. In
2194a238c70SJohn Marino            * this rounding mode, we need to round to 0 if:
2204a238c70SJohn Marino            *   _ |x| < 2^(emin-2), or
2214a238c70SJohn Marino            *   _ |x| = 2^(emin-2) and the absolute value of the exact
2224a238c70SJohn Marino            *     result is <= 2^(emin-2).
2234a238c70SJohn Marino            */
2244a238c70SJohn Marino           if (rnd_mode == MPFR_RNDN &&
2254a238c70SJohn Marino               (exp + 1 < __gmpfr_emin ||
2264a238c70SJohn Marino                (mpfr_powerof2_raw(x) &&
2274a238c70SJohn Marino                 (MPFR_IS_NEG(x) ? t <= 0 : t >= 0))))
2284a238c70SJohn Marino             rnd_mode = MPFR_RNDZ;
2294a238c70SJohn Marino           return mpfr_underflow(x, rnd_mode, MPFR_SIGN(x));
2304a238c70SJohn Marino         }
2314a238c70SJohn Marino       if (MPFR_UNLIKELY( exp > __gmpfr_emax) )
2324a238c70SJohn Marino         return mpfr_overflow (x, rnd_mode, MPFR_SIGN(x));
2334a238c70SJohn Marino     }
2344a238c70SJohn Marino   else if (MPFR_UNLIKELY (t != 0 && MPFR_IS_INF (x)))
2354a238c70SJohn Marino     {
2364a238c70SJohn Marino       /* We need to do the following because most MPFR functions are
2374a238c70SJohn Marino        * implemented in the following way:
2384a238c70SJohn Marino        *   Ziv's loop:
2394a238c70SJohn Marino        *   | Compute an approximation to the result and an error bound.
2404a238c70SJohn Marino        *   | Possible underflow/overflow detection -> return.
2414a238c70SJohn Marino        *   | If can_round, break (exit the loop).
2424a238c70SJohn Marino        *   | Otherwise, increase the working precision and loop.
2434a238c70SJohn Marino        *   Round the approximation in the target precision.  <== See below
2444a238c70SJohn Marino        *   Restore the flags (that could have been set due to underflows
2454a238c70SJohn Marino        *   or overflows during the internal computations).
2464a238c70SJohn Marino        *   Execute: return mpfr_check_range (...).
2474a238c70SJohn Marino        * The problem is that an overflow could be generated when rounding the
2484a238c70SJohn Marino        * approximation (in general, such an overflow could not be detected
2494a238c70SJohn Marino        * earlier), and the overflow flag is lost when the flags are restored.
2504a238c70SJohn Marino        * This can occur only when the rounding yields an exponent change
2514a238c70SJohn Marino        * and the new exponent is larger than the maximum exponent, so that
2524a238c70SJohn Marino        * an infinity is necessarily obtained.
2534a238c70SJohn Marino        * So, the simplest solution is to detect this overflow case here in
2544a238c70SJohn Marino        * mpfr_check_range, which is easy to do since the rounded result is
2554a238c70SJohn Marino        * necessarily an inexact infinity.
2564a238c70SJohn Marino        */
2574a238c70SJohn Marino       __gmpfr_flags |= MPFR_FLAGS_OVERFLOW;
2584a238c70SJohn Marino     }
2594a238c70SJohn Marino   MPFR_RET (t);  /* propagate inexact ternary value, unlike most functions */
2604a238c70SJohn Marino }
2614a238c70SJohn Marino 
2624a238c70SJohn Marino #undef mpfr_underflow_p
2634a238c70SJohn Marino 
2644a238c70SJohn Marino int
mpfr_underflow_p(void)2654a238c70SJohn Marino mpfr_underflow_p (void)
2664a238c70SJohn Marino {
2674a238c70SJohn Marino   return __gmpfr_flags & MPFR_FLAGS_UNDERFLOW;
2684a238c70SJohn Marino }
2694a238c70SJohn Marino 
2704a238c70SJohn Marino #undef mpfr_overflow_p
2714a238c70SJohn Marino 
2724a238c70SJohn Marino int
mpfr_overflow_p(void)2734a238c70SJohn Marino mpfr_overflow_p (void)
2744a238c70SJohn Marino {
2754a238c70SJohn Marino   return __gmpfr_flags & MPFR_FLAGS_OVERFLOW;
2764a238c70SJohn Marino }
2774a238c70SJohn Marino 
2784a238c70SJohn Marino #undef mpfr_divby0_p
2794a238c70SJohn Marino 
2804a238c70SJohn Marino int
mpfr_divby0_p(void)2814a238c70SJohn Marino mpfr_divby0_p (void)
2824a238c70SJohn Marino {
2834a238c70SJohn Marino   return __gmpfr_flags & MPFR_FLAGS_DIVBY0;
2844a238c70SJohn Marino }
2854a238c70SJohn Marino 
2864a238c70SJohn Marino #undef mpfr_nanflag_p
2874a238c70SJohn Marino 
2884a238c70SJohn Marino int
mpfr_nanflag_p(void)2894a238c70SJohn Marino mpfr_nanflag_p (void)
2904a238c70SJohn Marino {
2914a238c70SJohn Marino   return __gmpfr_flags & MPFR_FLAGS_NAN;
2924a238c70SJohn Marino }
2934a238c70SJohn Marino 
2944a238c70SJohn Marino #undef mpfr_inexflag_p
2954a238c70SJohn Marino 
2964a238c70SJohn Marino int
mpfr_inexflag_p(void)2974a238c70SJohn Marino mpfr_inexflag_p (void)
2984a238c70SJohn Marino {
2994a238c70SJohn Marino   return __gmpfr_flags & MPFR_FLAGS_INEXACT;
3004a238c70SJohn Marino }
3014a238c70SJohn Marino 
3024a238c70SJohn Marino #undef mpfr_erangeflag_p
3034a238c70SJohn Marino 
3044a238c70SJohn Marino int
mpfr_erangeflag_p(void)3054a238c70SJohn Marino mpfr_erangeflag_p (void)
3064a238c70SJohn Marino {
3074a238c70SJohn Marino   return __gmpfr_flags & MPFR_FLAGS_ERANGE;
3084a238c70SJohn Marino }
3094a238c70SJohn Marino 
3104a238c70SJohn Marino /* #undef mpfr_underflow */
3114a238c70SJohn Marino 
3124a238c70SJohn Marino /* Note: In the rounding to the nearest mode, mpfr_underflow
3134a238c70SJohn Marino    always rounds away from 0. In this rounding mode, you must call
3144a238c70SJohn Marino    mpfr_underflow with rnd_mode = MPFR_RNDZ if the exact result
3154a238c70SJohn Marino    is <= 2^(emin-2) in absolute value. */
3164a238c70SJohn Marino 
3174a238c70SJohn Marino int
mpfr_underflow(mpfr_ptr x,mpfr_rnd_t rnd_mode,int sign)3184a238c70SJohn Marino mpfr_underflow (mpfr_ptr x, mpfr_rnd_t rnd_mode, int sign)
3194a238c70SJohn Marino {
3204a238c70SJohn Marino   int inex;
3214a238c70SJohn Marino 
3224a238c70SJohn Marino   MPFR_ASSERT_SIGN (sign);
3234a238c70SJohn Marino 
3244a238c70SJohn Marino   if (MPFR_IS_LIKE_RNDZ(rnd_mode, sign < 0))
3254a238c70SJohn Marino     {
3264a238c70SJohn Marino       MPFR_SET_ZERO(x);
3274a238c70SJohn Marino       inex = -1;
3284a238c70SJohn Marino     }
3294a238c70SJohn Marino   else
3304a238c70SJohn Marino     {
3314a238c70SJohn Marino       mpfr_setmin (x, __gmpfr_emin);
3324a238c70SJohn Marino       inex = 1;
3334a238c70SJohn Marino     }
3344a238c70SJohn Marino   MPFR_SET_SIGN(x, sign);
3354a238c70SJohn Marino   __gmpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_UNDERFLOW;
3364a238c70SJohn Marino   return sign > 0 ? inex : -inex;
3374a238c70SJohn Marino }
3384a238c70SJohn Marino 
3394a238c70SJohn Marino /* #undef mpfr_overflow */
3404a238c70SJohn Marino 
3414a238c70SJohn Marino int
mpfr_overflow(mpfr_ptr x,mpfr_rnd_t rnd_mode,int sign)3424a238c70SJohn Marino mpfr_overflow (mpfr_ptr x, mpfr_rnd_t rnd_mode, int sign)
3434a238c70SJohn Marino {
3444a238c70SJohn Marino   int inex;
3454a238c70SJohn Marino 
3464a238c70SJohn Marino   MPFR_ASSERT_SIGN(sign);
3474a238c70SJohn Marino   if (MPFR_IS_LIKE_RNDZ(rnd_mode, sign < 0))
3484a238c70SJohn Marino     {
3494a238c70SJohn Marino       mpfr_setmax (x, __gmpfr_emax);
3504a238c70SJohn Marino       inex = -1;
3514a238c70SJohn Marino     }
3524a238c70SJohn Marino   else
3534a238c70SJohn Marino     {
3544a238c70SJohn Marino       MPFR_SET_INF(x);
3554a238c70SJohn Marino       inex = 1;
3564a238c70SJohn Marino     }
3574a238c70SJohn Marino   MPFR_SET_SIGN(x,sign);
3584a238c70SJohn Marino   __gmpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_OVERFLOW;
3594a238c70SJohn Marino   return sign > 0 ? inex : -inex;
3604a238c70SJohn Marino }
361