1 /* Exception flags and utilities. 2 3 Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. 4 Contributed by the AriC and Caramel 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 http://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 unsigned int MPFR_THREAD_ATTR __gmpfr_flags = 0; 26 27 mpfr_exp_t MPFR_THREAD_ATTR __gmpfr_emin = MPFR_EMIN_DEFAULT; 28 mpfr_exp_t MPFR_THREAD_ATTR __gmpfr_emax = MPFR_EMAX_DEFAULT; 29 30 #undef mpfr_get_emin 31 32 mpfr_exp_t 33 mpfr_get_emin (void) 34 { 35 return __gmpfr_emin; 36 } 37 38 #undef mpfr_set_emin 39 40 int 41 mpfr_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 54 mpfr_exp_t 55 mpfr_get_emin_min (void) 56 { 57 return MPFR_EMIN_MIN; 58 } 59 60 mpfr_exp_t 61 mpfr_get_emin_max (void) 62 { 63 return MPFR_EMIN_MAX; 64 } 65 66 #undef mpfr_get_emax 67 68 mpfr_exp_t 69 mpfr_get_emax (void) 70 { 71 return __gmpfr_emax; 72 } 73 74 #undef mpfr_set_emax 75 76 int 77 mpfr_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 90 mpfr_exp_t 91 mpfr_get_emax_min (void) 92 { 93 return MPFR_EMAX_MIN; 94 } 95 mpfr_exp_t 96 mpfr_get_emax_max (void) 97 { 98 return MPFR_EMAX_MAX; 99 } 100 101 102 #undef mpfr_clear_flags 103 104 void 105 mpfr_clear_flags (void) 106 { 107 __gmpfr_flags = 0; 108 } 109 110 #undef mpfr_clear_underflow 111 112 void 113 mpfr_clear_underflow (void) 114 { 115 __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_UNDERFLOW; 116 } 117 118 #undef mpfr_clear_overflow 119 120 void 121 mpfr_clear_overflow (void) 122 { 123 __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_OVERFLOW; 124 } 125 126 #undef mpfr_clear_divby0 127 128 void 129 mpfr_clear_divby0 (void) 130 { 131 __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_DIVBY0; 132 } 133 134 #undef mpfr_clear_nanflag 135 136 void 137 mpfr_clear_nanflag (void) 138 { 139 __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_NAN; 140 } 141 142 #undef mpfr_clear_inexflag 143 144 void 145 mpfr_clear_inexflag (void) 146 { 147 __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_INEXACT; 148 } 149 150 #undef mpfr_clear_erangeflag 151 152 void 153 mpfr_clear_erangeflag (void) 154 { 155 __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_ERANGE; 156 } 157 158 #undef mpfr_set_underflow 159 160 void 161 mpfr_set_underflow (void) 162 { 163 __gmpfr_flags |= MPFR_FLAGS_UNDERFLOW; 164 } 165 166 #undef mpfr_set_overflow 167 168 void 169 mpfr_set_overflow (void) 170 { 171 __gmpfr_flags |= MPFR_FLAGS_OVERFLOW; 172 } 173 174 #undef mpfr_set_divby0 175 176 void 177 mpfr_set_divby0 (void) 178 { 179 __gmpfr_flags |= MPFR_FLAGS_DIVBY0; 180 } 181 182 #undef mpfr_set_nanflag 183 184 void 185 mpfr_set_nanflag (void) 186 { 187 __gmpfr_flags |= MPFR_FLAGS_NAN; 188 } 189 190 #undef mpfr_set_inexflag 191 192 void 193 mpfr_set_inexflag (void) 194 { 195 __gmpfr_flags |= MPFR_FLAGS_INEXACT; 196 } 197 198 #undef mpfr_set_erangeflag 199 200 void 201 mpfr_set_erangeflag (void) 202 { 203 __gmpfr_flags |= MPFR_FLAGS_ERANGE; 204 } 205 206 207 #undef mpfr_check_range 208 209 int 210 mpfr_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 264 int 265 mpfr_underflow_p (void) 266 { 267 return __gmpfr_flags & MPFR_FLAGS_UNDERFLOW; 268 } 269 270 #undef mpfr_overflow_p 271 272 int 273 mpfr_overflow_p (void) 274 { 275 return __gmpfr_flags & MPFR_FLAGS_OVERFLOW; 276 } 277 278 #undef mpfr_divby0_p 279 280 int 281 mpfr_divby0_p (void) 282 { 283 return __gmpfr_flags & MPFR_FLAGS_DIVBY0; 284 } 285 286 #undef mpfr_nanflag_p 287 288 int 289 mpfr_nanflag_p (void) 290 { 291 return __gmpfr_flags & MPFR_FLAGS_NAN; 292 } 293 294 #undef mpfr_inexflag_p 295 296 int 297 mpfr_inexflag_p (void) 298 { 299 return __gmpfr_flags & MPFR_FLAGS_INEXACT; 300 } 301 302 #undef mpfr_erangeflag_p 303 304 int 305 mpfr_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 317 int 318 mpfr_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 341 int 342 mpfr_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