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