]> oss.titaniummirror.com Git - msp430-gcc.git/blobdiff - mpfr/exceptions.c
Imported gcc-4.4.3
[msp430-gcc.git] / mpfr / exceptions.c
diff --git a/mpfr/exceptions.c b/mpfr/exceptions.c
new file mode 100644 (file)
index 0000000..7d441cf
--- /dev/null
@@ -0,0 +1,336 @@
+/* Exception flags and utilities.
+
+Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+Contributed by the Arenaire and Cacao projects, INRIA.
+
+This file is part of the GNU MPFR Library.
+
+The GNU MPFR Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The GNU MPFR Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MPFR Library; see the file COPYING.LIB.  If not, write to
+the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+
+#include "mpfr-impl.h"
+
+unsigned int MPFR_THREAD_ATTR __gmpfr_flags = 0;
+
+mp_exp_t MPFR_THREAD_ATTR __gmpfr_emin = MPFR_EMIN_DEFAULT;
+mp_exp_t MPFR_THREAD_ATTR __gmpfr_emax = MPFR_EMAX_DEFAULT;
+
+#undef mpfr_get_emin
+
+mp_exp_t
+mpfr_get_emin (void)
+{
+  return __gmpfr_emin;
+}
+
+#undef mpfr_set_emin
+
+int
+mpfr_set_emin (mp_exp_t exponent)
+{
+  if (exponent >= MPFR_EMIN_MIN && exponent <= MPFR_EMIN_MAX)
+    {
+      __gmpfr_emin = exponent;
+      return 0;
+    }
+  else
+    {
+      return 1;
+    }
+}
+
+mp_exp_t
+mpfr_get_emin_min (void)
+{
+  return MPFR_EMIN_MIN;
+}
+
+mp_exp_t
+mpfr_get_emin_max (void)
+{
+  return MPFR_EMIN_MAX;
+}
+
+#undef mpfr_get_emax
+
+mp_exp_t
+mpfr_get_emax (void)
+{
+  return __gmpfr_emax;
+}
+
+#undef mpfr_set_emax
+
+int
+mpfr_set_emax (mp_exp_t exponent)
+{
+  if (exponent >= MPFR_EMAX_MIN && exponent <= MPFR_EMAX_MAX)
+    {
+      __gmpfr_emax = exponent;
+      return 0;
+    }
+  else
+    {
+      return 1;
+    }
+}
+
+mp_exp_t
+mpfr_get_emax_min (void)
+{
+  return MPFR_EMAX_MIN;
+}
+mp_exp_t
+mpfr_get_emax_max (void)
+{
+  return MPFR_EMAX_MAX;
+}
+
+
+#undef mpfr_clear_flags
+
+void
+mpfr_clear_flags (void)
+{
+  __gmpfr_flags = 0;
+}
+
+#undef mpfr_clear_underflow
+
+void
+mpfr_clear_underflow (void)
+{
+  __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_UNDERFLOW;
+}
+
+#undef mpfr_clear_overflow
+
+void
+mpfr_clear_overflow (void)
+{
+  __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_OVERFLOW;
+}
+
+#undef mpfr_clear_nanflag
+
+void
+mpfr_clear_nanflag (void)
+{
+  __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_NAN;
+}
+
+#undef mpfr_clear_inexflag
+
+void
+mpfr_clear_inexflag (void)
+{
+  __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_INEXACT;
+}
+
+#undef mpfr_clear_erangeflag
+
+void
+mpfr_clear_erangeflag (void)
+{
+  __gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_ERANGE;
+}
+
+#undef mpfr_clear_underflow
+
+void
+mpfr_set_underflow (void)
+{
+  __gmpfr_flags |= MPFR_FLAGS_UNDERFLOW;
+}
+
+#undef mpfr_clear_overflow
+
+void
+mpfr_set_overflow (void)
+{
+  __gmpfr_flags |= MPFR_FLAGS_OVERFLOW;
+}
+
+#undef mpfr_clear_nanflag
+
+void
+mpfr_set_nanflag (void)
+{
+  __gmpfr_flags |= MPFR_FLAGS_NAN;
+}
+
+#undef mpfr_clear_inexflag
+
+void
+mpfr_set_inexflag (void)
+{
+  __gmpfr_flags |= MPFR_FLAGS_INEXACT;
+}
+
+#undef mpfr_clear_erangeflag
+
+void
+mpfr_set_erangeflag (void)
+{
+  __gmpfr_flags |= MPFR_FLAGS_ERANGE;
+}
+
+
+#undef mpfr_check_range
+
+int
+mpfr_check_range (mpfr_ptr x, int t, mp_rnd_t rnd_mode)
+{
+  if (MPFR_LIKELY( MPFR_IS_PURE_FP(x)) )
+    { /* x is a non-zero FP */
+      mp_exp_t exp = MPFR_EXP (x);  /* Do not use MPFR_GET_EXP */
+      if (MPFR_UNLIKELY( exp < __gmpfr_emin) )
+        {
+          /* The following test is necessary because in the rounding to the
+           * nearest mode, mpfr_underflow always rounds away from 0. In
+           * this rounding mode, we need to round to 0 if:
+           *   _ |x| < 2^(emin-2), or
+           *   _ |x| = 2^(emin-2) and the absolute value of the exact
+           *     result is <= 2^(emin-2).
+           */
+          if (rnd_mode == GMP_RNDN &&
+              (exp + 1 < __gmpfr_emin ||
+               (mpfr_powerof2_raw(x) &&
+                (MPFR_IS_NEG(x) ? t <= 0 : t >= 0))))
+            rnd_mode = GMP_RNDZ;
+          return mpfr_underflow(x, rnd_mode, MPFR_SIGN(x));
+        }
+      if (MPFR_UNLIKELY( exp > __gmpfr_emax) )
+        return mpfr_overflow(x, rnd_mode, MPFR_SIGN(x));
+    }
+  else if (MPFR_UNLIKELY (t != 0 && MPFR_IS_INF (x)))
+    {
+      /* We need to do the following because most MPFR functions are
+       * implemented in the following way:
+       *   Ziv's loop:
+       *   | Compute an approximation to the result and an error bound.
+       *   | Possible underflow/overflow detection -> return.
+       *   | If can_round, break (exit the loop).
+       *   | Otherwise, increase the working precision and loop.
+       *   Round the approximation in the target precision.
+       *   Restore the flags (that could have been set due to underflows
+       *   or overflows during the internal computations).
+       *   Execute: return mpfr_check_range (...).
+       * The problem is that an overflow could be generated when rounding the
+       * approximation (in general, such an overflow could not be detected
+       * earlier), and the overflow flag is lost when the flags are restored.
+       * So, the simplest solution is to detect this overflow case here in
+       * mpfr_check_range, which is easy to do since the rounded result is
+       * necessarily an inexact infinity.
+       */
+      __gmpfr_flags |= MPFR_FLAGS_OVERFLOW;
+    }
+  MPFR_RET (t);  /* propagate inexact ternary value, unlike most functions */
+}
+
+#undef mpfr_underflow_p
+
+int
+mpfr_underflow_p (void)
+{
+  return __gmpfr_flags & MPFR_FLAGS_UNDERFLOW;
+}
+
+#undef mpfr_overflow_p
+
+int
+mpfr_overflow_p (void)
+{
+  return __gmpfr_flags & MPFR_FLAGS_OVERFLOW;
+}
+
+#undef mpfr_nanflag_p
+
+int
+mpfr_nanflag_p (void)
+{
+  return __gmpfr_flags & MPFR_FLAGS_NAN;
+}
+
+#undef mpfr_inexflag_p
+
+int
+mpfr_inexflag_p (void)
+{
+  return __gmpfr_flags & MPFR_FLAGS_INEXACT;
+}
+
+#undef mpfr_erangeflag_p
+
+int
+mpfr_erangeflag_p (void)
+{
+  return __gmpfr_flags & MPFR_FLAGS_ERANGE;
+}
+
+/* #undef mpfr_underflow */
+
+/* Note: In the rounding to the nearest mode, mpfr_underflow
+   always rounds away from 0. In this rounding mode, you must call
+   mpfr_underflow with rnd_mode = GMP_RNDZ if the exact result
+   is <= 2^(emin-2) in absolute value. */
+
+int
+mpfr_underflow (mpfr_ptr x, mp_rnd_t rnd_mode, int sign)
+{
+  int inex;
+
+  MPFR_ASSERT_SIGN (sign);
+
+  if (rnd_mode == GMP_RNDN
+      || MPFR_IS_RNDUTEST_OR_RNDDNOTTEST(rnd_mode, MPFR_IS_POS_SIGN (sign)))
+    {
+      mpfr_setmin (x, __gmpfr_emin);
+      inex = 1;
+    }
+  else
+    {
+      MPFR_SET_ZERO(x);
+      inex = -1;
+    }
+  MPFR_SET_SIGN(x, sign);
+  __gmpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_UNDERFLOW;
+  return sign > 0 ? inex : -inex;
+}
+
+/* #undef mpfr_overflow */
+
+int
+mpfr_overflow (mpfr_ptr x, mp_rnd_t rnd_mode, int sign)
+{
+  int inex;
+
+  MPFR_ASSERT_SIGN(sign);
+  MPFR_CLEAR_FLAGS(x);
+  if (rnd_mode == GMP_RNDN
+      || MPFR_IS_RNDUTEST_OR_RNDDNOTTEST(rnd_mode, sign > 0))
+    {
+      MPFR_SET_INF(x);
+      inex = 1;
+    }
+  else
+    {
+      mpfr_setmax (x, __gmpfr_emax);
+      inex = -1;
+    }
+  MPFR_SET_SIGN(x,sign);
+  __gmpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_OVERFLOW;
+  return sign > 0 ? inex : -inex;
+}