1 /* Exception flags and utilities. 2 3 Copyright 2001-2016 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 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 MPFR_THREAD_ATTR unsigned int __gmpfr_flags = 0; 26 27 MPFR_THREAD_ATTR mpfr_exp_t __gmpfr_emin = MPFR_EMIN_DEFAULT; 28 MPFR_THREAD_ATTR mpfr_exp_t __gmpfr_emax = MPFR_EMAX_DEFAULT; 29 30 #ifdef MPFR_WIN_THREAD_SAFE_DLL 31 unsigned int * __gmpfr_flags_f() { return &__gmpfr_flags; } 32 mpfr_exp_t * __gmpfr_emin_f() { return &__gmpfr_emin; } 33 mpfr_exp_t * __gmpfr_emax_f() { return &__gmpfr_emax; } 34 #endif 35 36 #undef mpfr_get_emin 37 38 mpfr_exp_t 39 mpfr_get_emin (void) 40 { 41 return __gmpfr_emin; 42 } 43 44 #undef mpfr_set_emin 45 46 int 47 mpfr_set_emin (mpfr_exp_t exponent) 48 { 49 if (exponent >= MPFR_EMIN_MIN && exponent <= MPFR_EMIN_MAX) 50 { 51 __gmpfr_emin = exponent; 52 return 0; 53 } 54 else 55 { 56 return 1; 57 } 58 } 59 60 mpfr_exp_t 61 mpfr_get_emin_min (void) 62 { 63 return MPFR_EMIN_MIN; 64 } 65 66 mpfr_exp_t 67 mpfr_get_emin_max (void) 68 { 69 return MPFR_EMIN_MAX; 70 } 71 72 #undef mpfr_get_emax 73 74 mpfr_exp_t 75 mpfr_get_emax (void) 76 { 77 return __gmpfr_emax; 78 } 79 80 #undef mpfr_set_emax 81 82 int 83 mpfr_set_emax (mpfr_exp_t exponent) 84 { 85 if (exponent >= MPFR_EMAX_MIN && exponent <= MPFR_EMAX_MAX) 86 { 87 __gmpfr_emax = exponent; 88 return 0; 89 } 90 else 91 { 92 return 1; 93 } 94 } 95 96 mpfr_exp_t 97 mpfr_get_emax_min (void) 98 { 99 return MPFR_EMAX_MIN; 100 } 101 mpfr_exp_t 102 mpfr_get_emax_max (void) 103 { 104 return MPFR_EMAX_MAX; 105 } 106 107 108 #undef mpfr_clear_flags 109 110 void 111 mpfr_clear_flags (void) 112 { 113 __gmpfr_flags = 0; 114 } 115 116 #undef mpfr_clear_underflow 117 118 void 119 mpfr_clear_underflow (void) 120 { 121 __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_UNDERFLOW; 122 } 123 124 #undef mpfr_clear_overflow 125 126 void 127 mpfr_clear_overflow (void) 128 { 129 __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_OVERFLOW; 130 } 131 132 #undef mpfr_clear_divby0 133 134 void 135 mpfr_clear_divby0 (void) 136 { 137 __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_DIVBY0; 138 } 139 140 #undef mpfr_clear_nanflag 141 142 void 143 mpfr_clear_nanflag (void) 144 { 145 __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_NAN; 146 } 147 148 #undef mpfr_clear_inexflag 149 150 void 151 mpfr_clear_inexflag (void) 152 { 153 __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_INEXACT; 154 } 155 156 #undef mpfr_clear_erangeflag 157 158 void 159 mpfr_clear_erangeflag (void) 160 { 161 __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_ERANGE; 162 } 163 164 #undef mpfr_set_underflow 165 166 void 167 mpfr_set_underflow (void) 168 { 169 __gmpfr_flags |= MPFR_FLAGS_UNDERFLOW; 170 } 171 172 #undef mpfr_set_overflow 173 174 void 175 mpfr_set_overflow (void) 176 { 177 __gmpfr_flags |= MPFR_FLAGS_OVERFLOW; 178 } 179 180 #undef mpfr_set_divby0 181 182 void 183 mpfr_set_divby0 (void) 184 { 185 __gmpfr_flags |= MPFR_FLAGS_DIVBY0; 186 } 187 188 #undef mpfr_set_nanflag 189 190 void 191 mpfr_set_nanflag (void) 192 { 193 __gmpfr_flags |= MPFR_FLAGS_NAN; 194 } 195 196 #undef mpfr_set_inexflag 197 198 void 199 mpfr_set_inexflag (void) 200 { 201 __gmpfr_flags |= MPFR_FLAGS_INEXACT; 202 } 203 204 #undef mpfr_set_erangeflag 205 206 void 207 mpfr_set_erangeflag (void) 208 { 209 __gmpfr_flags |= MPFR_FLAGS_ERANGE; 210 } 211 212 213 #undef mpfr_check_range 214 215 int 216 mpfr_check_range (mpfr_ptr x, int t, mpfr_rnd_t rnd_mode) 217 { 218 if (MPFR_LIKELY( MPFR_IS_PURE_FP(x)) ) 219 { /* x is a non-zero FP */ 220 mpfr_exp_t exp = MPFR_EXP (x); /* Do not use MPFR_GET_EXP */ 221 if (MPFR_UNLIKELY( exp < __gmpfr_emin) ) 222 { 223 /* The following test is necessary because in the rounding to the 224 * nearest mode, mpfr_underflow always rounds away from 0. In 225 * this rounding mode, we need to round to 0 if: 226 * _ |x| < 2^(emin-2), or 227 * _ |x| = 2^(emin-2) and the absolute value of the exact 228 * result is <= 2^(emin-2). 229 */ 230 if (rnd_mode == MPFR_RNDN && 231 (exp + 1 < __gmpfr_emin || 232 (mpfr_powerof2_raw(x) && 233 (MPFR_IS_NEG(x) ? t <= 0 : t >= 0)))) 234 rnd_mode = MPFR_RNDZ; 235 return mpfr_underflow(x, rnd_mode, MPFR_SIGN(x)); 236 } 237 if (MPFR_UNLIKELY( exp > __gmpfr_emax) ) 238 return mpfr_overflow (x, rnd_mode, MPFR_SIGN(x)); 239 } 240 else if (MPFR_UNLIKELY (t != 0 && MPFR_IS_INF (x))) 241 { 242 /* We need to do the following because most MPFR functions are 243 * implemented in the following way: 244 * Ziv's loop: 245 * | Compute an approximation to the result and an error bound. 246 * | Possible underflow/overflow detection -> return. 247 * | If can_round, break (exit the loop). 248 * | Otherwise, increase the working precision and loop. 249 * Round the approximation in the target precision. <== See below 250 * Restore the flags (that could have been set due to underflows 251 * or overflows during the internal computations). 252 * Execute: return mpfr_check_range (...). 253 * The problem is that an overflow could be generated when rounding the 254 * approximation (in general, such an overflow could not be detected 255 * earlier), and the overflow flag is lost when the flags are restored. 256 * This can occur only when the rounding yields an exponent change 257 * and the new exponent is larger than the maximum exponent, so that 258 * an infinity is necessarily obtained. 259 * So, the simplest solution is to detect this overflow case here in 260 * mpfr_check_range, which is easy to do since the rounded result is 261 * necessarily an inexact infinity. 262 */ 263 __gmpfr_flags |= MPFR_FLAGS_OVERFLOW; 264 } 265 MPFR_RET (t); /* propagate inexact ternary value, unlike most functions */ 266 } 267 268 #undef mpfr_underflow_p 269 270 int 271 mpfr_underflow_p (void) 272 { 273 return __gmpfr_flags & MPFR_FLAGS_UNDERFLOW; 274 } 275 276 #undef mpfr_overflow_p 277 278 int 279 mpfr_overflow_p (void) 280 { 281 return __gmpfr_flags & MPFR_FLAGS_OVERFLOW; 282 } 283 284 #undef mpfr_divby0_p 285 286 int 287 mpfr_divby0_p (void) 288 { 289 return __gmpfr_flags & MPFR_FLAGS_DIVBY0; 290 } 291 292 #undef mpfr_nanflag_p 293 294 int 295 mpfr_nanflag_p (void) 296 { 297 return __gmpfr_flags & MPFR_FLAGS_NAN; 298 } 299 300 #undef mpfr_inexflag_p 301 302 int 303 mpfr_inexflag_p (void) 304 { 305 return __gmpfr_flags & MPFR_FLAGS_INEXACT; 306 } 307 308 #undef mpfr_erangeflag_p 309 310 int 311 mpfr_erangeflag_p (void) 312 { 313 return __gmpfr_flags & MPFR_FLAGS_ERANGE; 314 } 315 316 /* #undef mpfr_underflow */ 317 318 /* Note: In the rounding to the nearest mode, mpfr_underflow 319 always rounds away from 0. In this rounding mode, you must call 320 mpfr_underflow with rnd_mode = MPFR_RNDZ if the exact result 321 is <= 2^(emin-2) in absolute value. */ 322 323 int 324 mpfr_underflow (mpfr_ptr x, mpfr_rnd_t rnd_mode, int sign) 325 { 326 int inex; 327 328 MPFR_ASSERT_SIGN (sign); 329 330 if (MPFR_IS_LIKE_RNDZ(rnd_mode, sign < 0)) 331 { 332 MPFR_SET_ZERO(x); 333 inex = -1; 334 } 335 else 336 { 337 mpfr_setmin (x, __gmpfr_emin); 338 inex = 1; 339 } 340 MPFR_SET_SIGN(x, sign); 341 __gmpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_UNDERFLOW; 342 return sign > 0 ? inex : -inex; 343 } 344 345 /* #undef mpfr_overflow */ 346 347 int 348 mpfr_overflow (mpfr_ptr x, mpfr_rnd_t rnd_mode, int sign) 349 { 350 int inex; 351 352 MPFR_ASSERT_SIGN(sign); 353 if (MPFR_IS_LIKE_RNDZ(rnd_mode, sign < 0)) 354 { 355 mpfr_setmax (x, __gmpfr_emax); 356 inex = -1; 357 } 358 else 359 { 360 MPFR_SET_INF(x); 361 inex = 1; 362 } 363 MPFR_SET_SIGN(x,sign); 364 __gmpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_OVERFLOW; 365 return sign > 0 ? inex : -inex; 366 } 367