1/* Exception flags and utilities. 2 3Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. 4Contributed by the AriC and Caramel 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_divby0 127 128void 129mpfr_clear_divby0 (void) 130{ 131 __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_DIVBY0; 132} 133 134#undef mpfr_clear_nanflag 135 136void 137mpfr_clear_nanflag (void) 138{ 139 __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_NAN; 140} 141 142#undef mpfr_clear_inexflag 143 144void 145mpfr_clear_inexflag (void) 146{ 147 __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_INEXACT; 148} 149 150#undef mpfr_clear_erangeflag 151 152void 153mpfr_clear_erangeflag (void) 154{ 155 __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_ERANGE; 156} 157 158#undef mpfr_set_underflow 159 160void 161mpfr_set_underflow (void) 162{ 163 __gmpfr_flags |= MPFR_FLAGS_UNDERFLOW; 164} 165 166#undef mpfr_set_overflow 167 168void 169mpfr_set_overflow (void) 170{ 171 __gmpfr_flags |= MPFR_FLAGS_OVERFLOW; 172} 173 174#undef mpfr_set_divby0 175 176void 177mpfr_set_divby0 (void) 178{ 179 __gmpfr_flags |= MPFR_FLAGS_DIVBY0; 180} 181 182#undef mpfr_set_nanflag 183 184void 185mpfr_set_nanflag (void) 186{ 187 __gmpfr_flags |= MPFR_FLAGS_NAN; 188} 189 190#undef mpfr_set_inexflag 191 192void 193mpfr_set_inexflag (void) 194{ 195 __gmpfr_flags |= MPFR_FLAGS_INEXACT; 196} 197 198#undef mpfr_set_erangeflag 199 200void 201mpfr_set_erangeflag (void) 202{ 203 __gmpfr_flags |= MPFR_FLAGS_ERANGE; 204} 205 206 207#undef mpfr_check_range 208 209int 210mpfr_check_range (mpfr_ptr x, int t, mpfr_rnd_t rnd_mode) 211{ 212 if (MPFR_LIKELY( MPFR_IS_PURE_FP(x)) ) 213 { /* x is a non-zero FP */ 214 mpfr_exp_t exp = MPFR_EXP (x); /* Do not use MPFR_GET_EXP */ 215 if (MPFR_UNLIKELY( exp < __gmpfr_emin) ) 216 { 217 /* The following test is necessary because in the rounding to the 218 * nearest mode, mpfr_underflow always rounds away from 0. In 219 * this rounding mode, we need to round to 0 if: 220 * _ |x| < 2^(emin-2), or 221 * _ |x| = 2^(emin-2) and the absolute value of the exact 222 * result is <= 2^(emin-2). 223 */ 224 if (rnd_mode == MPFR_RNDN && 225 (exp + 1 < __gmpfr_emin || 226 (mpfr_powerof2_raw(x) && 227 (MPFR_IS_NEG(x) ? t <= 0 : t >= 0)))) 228 rnd_mode = MPFR_RNDZ; 229 return mpfr_underflow(x, rnd_mode, MPFR_SIGN(x)); 230 } 231 if (MPFR_UNLIKELY( exp > __gmpfr_emax) ) 232 return mpfr_overflow (x, rnd_mode, MPFR_SIGN(x)); 233 } 234 else if (MPFR_UNLIKELY (t != 0 && MPFR_IS_INF (x))) 235 { 236 /* We need to do the following because most MPFR functions are 237 * implemented in the following way: 238 * Ziv's loop: 239 * | Compute an approximation to the result and an error bound. 240 * | Possible underflow/overflow detection -> return. 241 * | If can_round, break (exit the loop). 242 * | Otherwise, increase the working precision and loop. 243 * Round the approximation in the target precision. <== See below 244 * Restore the flags (that could have been set due to underflows 245 * or overflows during the internal computations). 246 * Execute: return mpfr_check_range (...). 247 * The problem is that an overflow could be generated when rounding the 248 * approximation (in general, such an overflow could not be detected 249 * earlier), and the overflow flag is lost when the flags are restored. 250 * This can occur only when the rounding yields an exponent change 251 * and the new exponent is larger than the maximum exponent, so that 252 * an infinity is necessarily obtained. 253 * So, the simplest solution is to detect this overflow case here in 254 * mpfr_check_range, which is easy to do since the rounded result is 255 * necessarily an inexact infinity. 256 */ 257 __gmpfr_flags |= MPFR_FLAGS_OVERFLOW; 258 } 259 MPFR_RET (t); /* propagate inexact ternary value, unlike most functions */ 260} 261 262#undef mpfr_underflow_p 263 264int 265mpfr_underflow_p (void) 266{ 267 return __gmpfr_flags & MPFR_FLAGS_UNDERFLOW; 268} 269 270#undef mpfr_overflow_p 271 272int 273mpfr_overflow_p (void) 274{ 275 return __gmpfr_flags & MPFR_FLAGS_OVERFLOW; 276} 277 278#undef mpfr_divby0_p 279 280int 281mpfr_divby0_p (void) 282{ 283 return __gmpfr_flags & MPFR_FLAGS_DIVBY0; 284} 285 286#undef mpfr_nanflag_p 287 288int 289mpfr_nanflag_p (void) 290{ 291 return __gmpfr_flags & MPFR_FLAGS_NAN; 292} 293 294#undef mpfr_inexflag_p 295 296int 297mpfr_inexflag_p (void) 298{ 299 return __gmpfr_flags & MPFR_FLAGS_INEXACT; 300} 301 302#undef mpfr_erangeflag_p 303 304int 305mpfr_erangeflag_p (void) 306{ 307 return __gmpfr_flags & MPFR_FLAGS_ERANGE; 308} 309 310/* #undef mpfr_underflow */ 311 312/* Note: In the rounding to the nearest mode, mpfr_underflow 313 always rounds away from 0. In this rounding mode, you must call 314 mpfr_underflow with rnd_mode = MPFR_RNDZ if the exact result 315 is <= 2^(emin-2) in absolute value. */ 316 317int 318mpfr_underflow (mpfr_ptr x, mpfr_rnd_t rnd_mode, int sign) 319{ 320 int inex; 321 322 MPFR_ASSERT_SIGN (sign); 323 324 if (MPFR_IS_LIKE_RNDZ(rnd_mode, sign < 0)) 325 { 326 MPFR_SET_ZERO(x); 327 inex = -1; 328 } 329 else 330 { 331 mpfr_setmin (x, __gmpfr_emin); 332 inex = 1; 333 } 334 MPFR_SET_SIGN(x, sign); 335 __gmpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_UNDERFLOW; 336 return sign > 0 ? inex : -inex; 337} 338 339/* #undef mpfr_overflow */ 340 341int 342mpfr_overflow (mpfr_ptr x, mpfr_rnd_t rnd_mode, int sign) 343{ 344 int inex; 345 346 MPFR_ASSERT_SIGN(sign); 347 if (MPFR_IS_LIKE_RNDZ(rnd_mode, sign < 0)) 348 { 349 mpfr_setmax (x, __gmpfr_emax); 350 inex = -1; 351 } 352 else 353 { 354 MPFR_SET_INF(x); 355 inex = 1; 356 } 357 MPFR_SET_SIGN(x,sign); 358 __gmpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_OVERFLOW; 359 return sign > 0 ? inex : -inex; 360} 361