From 8eb22ba63830dbf829b9faa742c68438c43992d9 Mon Sep 17 00:00:00 2001 From: pelissip Date: Wed, 29 Sep 2004 12:27:36 +0000 Subject: Add mpfr_clear_erangeflag and mpfr_erangeflag_p. Add test for theses two functions. mpfr_get_[s/u][i/j] have a deterministic behavior in case of OVERFLOW. (Return the MINIMUM or the MAXIMUM in the current type, and set ERANGE_flag). git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@3007 280ebfd0-de03-0410-8827-d642c229c3f4 --- exceptions.c | 16 +++++++++++ get_si.c | 12 ++++++--- get_sj.c | 20 ++++++++++++-- get_ui.c | 10 +++++-- get_uj.c | 18 ++++++++++++- mpfr-impl.h | 8 +++--- set_sj.c | 7 +++++ set_uj.c | 7 +++++ tests/texceptions.c | 10 +++++++ tests/tget_sj.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/tset_si.c | 58 +++++++++++++++++++++++++++++++++++++++- tests/tset_sj.c | 7 +++++ 12 files changed, 237 insertions(+), 12 deletions(-) diff --git a/exceptions.c b/exceptions.c index 8ca0a1e48..a144c0ffa 100644 --- a/exceptions.c +++ b/exceptions.c @@ -138,6 +138,14 @@ 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_check_range int @@ -200,6 +208,14 @@ 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_set_underflow */ /* Note: In the rounding to the nearest mode, mpfr_set_underflow diff --git a/get_si.c b/get_si.c index fd55f29eb..5ec6b3e86 100644 --- a/get_si.c +++ b/get_si.c @@ -19,7 +19,7 @@ along with the MPFR Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - +#include #include "mpfr-impl.h" long @@ -29,8 +29,14 @@ mpfr_get_si (mpfr_srcptr f, mp_rnd_t rnd) long s; mpfr_t x; - if (!mpfr_fits_slong_p (f, rnd) || MPFR_IS_ZERO(f)) - return (long) 0; + if (!mpfr_fits_slong_p (f, rnd)) + { + MPFR_SET_ERANGE (); + return MPFR_IS_NEG (f) ? LONG_MIN : LONG_MAX; + } + + if (MPFR_IS_ZERO (f)) + return (long) 0; /* determine prec of long */ for (s = LONG_MIN, prec = 0; s != 0; s /= 2, prec ++); diff --git a/get_sj.c b/get_sj.c index 08d1d0106..062f30c38 100644 --- a/get_sj.c +++ b/get_sj.c @@ -23,6 +23,13 @@ MA 02111-1307, USA. */ # include "config.h" /* for a build within gmp */ #endif +/* The ISO C99 standard specifies that in C++ implementations the + INTMAX_MAX, ... macros should only be defined if explicitly requested. */ +#if defined __cplusplus +# define __STDC_LIMIT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + #ifdef HAVE_STDINT_H # include #endif @@ -41,6 +48,14 @@ mpfr_get_sj (mpfr_srcptr f, mpfr_rnd_t rnd) mp_prec_t prec; mpfr_t x; + if (!mpfr_fits_intmax_p (f, rnd)) + { + MPFR_SET_ERANGE (); + return MPFR_IS_NEG (f) ? INTMAX_MIN : INTMAX_MAX; + } + if (MPFR_IS_ZERO (f)) + return (intmax_t) 0; + /* determine the precision of intmax_t */ for (r = INTMAX_MIN, prec = 0; r != 0; r /= 2, prec++) { @@ -63,8 +78,9 @@ mpfr_get_sj (mpfr_srcptr f, mpfr_rnd_t rnd) xp = MPFR_MANT (x); sh = MPFR_GET_EXP (x); - MPFR_ASSERTN (sh <= prec); - if (INTMAX_MIN + INTMAX_MAX != 0 && MPFR_UNLIKELY (sh == prec)) + MPFR_ASSERTN ((mp_prec_t) sh <= prec); + if (INTMAX_MIN + INTMAX_MAX != 0 + && MPFR_UNLIKELY ((mp_prec_t) sh == prec)) { /* 2's complement and x <= INTMAX_MIN: in the case mp_limb_t has the same size as intmax_t, we cannot use the code in diff --git a/get_ui.c b/get_ui.c index 1d5d286d0..cd238b9a5 100644 --- a/get_ui.c +++ b/get_ui.c @@ -19,7 +19,7 @@ along with the MPFR Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - +#include #include "mpfr-impl.h" unsigned long @@ -31,7 +31,13 @@ mpfr_get_ui (mpfr_srcptr f, mp_rnd_t rnd) mp_size_t n; mp_exp_t exp; - if (!mpfr_fits_ulong_p (f, rnd) || MPFR_IS_ZERO(f)) + if (!mpfr_fits_ulong_p (f, rnd)) + { + MPFR_SET_ERANGE (); + return MPFR_IS_NEG (f) ? 0 : ULONG_MAX; + } + + if (MPFR_IS_ZERO (f)) return (unsigned long) 0; for (s = ULONG_MAX, prec = 0; s != 0; s >>= 1, prec ++); diff --git a/get_uj.c b/get_uj.c index 34b700eef..1d1e29042 100644 --- a/get_uj.c +++ b/get_uj.c @@ -23,6 +23,13 @@ MA 02111-1307, USA. */ # include "config.h" /* for a build within gmp */ #endif +/* The ISO C99 standard specifies that in C++ implementations the + INTMAX_MAX, ... macros should only be defined if explicitly requested. */ +#if defined __cplusplus +# define __STDC_LIMIT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + #ifdef HAVE_STDINT_H # include #endif @@ -41,6 +48,15 @@ mpfr_get_uj (mpfr_srcptr f, mpfr_rnd_t rnd) mp_prec_t prec; mpfr_t x; + if (!mpfr_fits_uintmax_p (f, rnd)) + { + MPFR_SET_ERANGE (); + return MPFR_IS_NEG (f) ? (uintmax_t) 0 : UINTMAX_MAX; + } + + if (MPFR_IS_ZERO (f)) + return (uintmax_t) 0; + /* determine the precision of uintmax_t */ for (r = UINTMAX_MAX, prec = 0; r != 0; r /= 2, prec++) { } @@ -59,7 +75,7 @@ mpfr_get_uj (mpfr_srcptr f, mpfr_rnd_t rnd) MPFR_ASSERTN (MPFR_IS_POS (x)); xp = MPFR_MANT (x); sh = MPFR_GET_EXP (x); - MPFR_ASSERTN (sh <= prec); + MPFR_ASSERTN ((mp_prec_t) sh <= prec); for (n = MPFR_LIMB_SIZE(x) - 1; n >= 0; n--) { sh -= BITS_PER_MP_LIMB; diff --git a/mpfr-impl.h b/mpfr-impl.h index 3576b7975..4cc131504 100644 --- a/mpfr-impl.h +++ b/mpfr-impl.h @@ -154,11 +154,11 @@ typedef unsigned long int mpfr_uexp_t; # define mp_exp_unsigned_t mpfr_uexp_t #endif -#if MPFR_PREC_FORMAT == 1 +#if _MPFR_PREC_FORMAT == 1 # define MPFR_INTPREC_MAX (USHRT_MAX & ~(unsigned int) (BITS_PER_MP_LIMB - 1)) -#elif MPFR_PREC_FORMAT == 2 +#elif _MPFR_PREC_FORMAT == 2 # define MPFR_INTPREC_MAX (UINT_MAX & ~(unsigned int) (BITS_PER_MP_LIMB - 1)) -#elif MPFR_PREC_FORMAT == 3 +#elif _MPFR_PREC_FORMAT == 3 # define MPFR_INTPREC_MAX (ULONG_MAX & ~(unsigned long) (BITS_PER_MP_LIMB - 1)) #else # error "Invalid MPFR Prec format" @@ -473,6 +473,8 @@ long double __gmpfr_longdouble_volatile _MPFR_PROTO ((long double)) ATTRIBUTE_CO (I) ? ((__gmpfr_flags |= MPFR_FLAGS_INEXACT), (I)) : 0 #define MPFR_RET_NAN return (__gmpfr_flags |= MPFR_FLAGS_NAN), 0 +#define MPFR_SET_ERANGE() (__gmpfr_flags |= MPFR_FLAGS_ERANGE) + /* Heap Memory gestion */ typedef union { mp_size_t s; mp_limb_t l; } mpfr_size_limb_t; #define MPFR_GET_ALLOC_SIZE(x) \ diff --git a/set_sj.c b/set_sj.c index 509b2a810..f6fa03c49 100644 --- a/set_sj.c +++ b/set_sj.c @@ -23,6 +23,13 @@ MA 02111-1307, USA. */ # include "config.h" /* for a build within gmp */ #endif +/* The ISO C99 standard specifies that in C++ implementations the + INTMAX_MAX, ... macros should only be defined if explicitly requested. */ +#if defined __cplusplus +# define __STDC_LIMIT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + #ifdef HAVE_STDINT_H # include #endif diff --git a/set_uj.c b/set_uj.c index a8f413fd7..abd06cefa 100644 --- a/set_uj.c +++ b/set_uj.c @@ -23,6 +23,13 @@ MA 02111-1307, USA. */ # include "config.h" /* for a build within gmp */ #endif +/* The ISO C99 standard specifies that in C++ implementations the + INTMAX_MAX, ... macros should only be defined if explicitly requested. */ +#if defined(__cplusplus) +# define __STDC_LIMIT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + #ifdef HAVE_STDINT_H # include #endif diff --git a/tests/texceptions.c b/tests/texceptions.c index 73e53b3c2..0d99daaec 100644 --- a/tests/texceptions.c +++ b/tests/texceptions.c @@ -101,22 +101,32 @@ check_flags (void) mpfr_mul_2exp (x, x, 1024, GMP_RNDN); if (!(mpfr_overflow_p)()) ERROR("ERROR: No overflow detected!\n"); + (mpfr_clear_underflow)(); mpfr_set_ui (x, 1, GMP_RNDN); mpfr_div_2exp (x, x, 1025, GMP_RNDN); if (!(mpfr_underflow_p)()) ERROR("ERROR: No underflow detected!\n"); + (mpfr_clear_nanflag)(); MPFR_SET_NAN(x); mpfr_add (x, x, x, GMP_RNDN); if (!(mpfr_nanflag_p)()) ERROR("ERROR: No NaN flag!\n"); + (mpfr_clear_inexflag)(); mpfr_set_ui(x, 2, GMP_RNDN); mpfr_cos(x, x, GMP_RNDN); if (!(mpfr_inexflag_p)()) ERROR("ERROR: No inexact flag!\n"); + (mpfr_clear_erangeflag) (); + mpfr_set_ui (x, 1, GMP_RNDN); + mpfr_mul_2exp (x, x, 1024, GMP_RNDN); + mpfr_get_ui (x, GMP_RNDN); + if (!(mpfr_erangeflag_p)()) + ERROR ("ERROR: No erange flag!\n"); + mpfr_clear(x); } diff --git a/tests/tget_sj.c b/tests/tget_sj.c index 869977845..77f3dde5c 100644 --- a/tests/tget_sj.c +++ b/tests/tget_sj.c @@ -26,6 +26,13 @@ MA 02111-1307, USA. */ #include #include +/* The ISO C99 standard specifies that in C++ implementations the + INTMAX_MAX, ... macros should only be defined if explicitly requested. */ +#if defined __cplusplus +# define __STDC_LIMIT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + #ifdef HAVE_STDINT_H # include #endif @@ -127,6 +134,73 @@ check_uj (uintmax_t u, mpfr_ptr x) mpfr_clear (y); } +static void +check_erange (void) +{ + mpfr_t x; + uintmax_t dl; + intmax_t d; + + /* Test for ERANGE flag + correct behaviour if overflow */ + + mpfr_init2 (x, 256); + mpfr_set_uj (x, UINTMAX_MAX, GMP_RNDN); + mpfr_clear_erangeflag (); + dl = mpfr_get_uj (x, GMP_RNDN); + if (dl != UINTMAX_MAX || mpfr_erangeflag_p ()) + { + printf ("ERROR for get_uj + ERANGE + UINTMAX_MAX (1)\n"); + exit (1); + } + mpfr_add_ui (x, x, 1, GMP_RNDN); + dl = mpfr_get_uj (x, GMP_RNDN); + if (dl != UINTMAX_MAX || !mpfr_erangeflag_p ()) + { + printf ("ERROR for get_uj + ERANGE + UINTMAX_MAX (2)\n"); + exit (1); + } + mpfr_set_sj (x, -1, GMP_RNDN); + mpfr_clear_erangeflag (); + dl = mpfr_get_uj (x, GMP_RNDN); + if (dl != 0 || !mpfr_erangeflag_p ()) + { + printf ("ERROR for get_uj + ERANGE + -1 \n"); + exit (1); + } + mpfr_set_sj (x, INTMAX_MAX, GMP_RNDN); + mpfr_clear_erangeflag (); + d = mpfr_get_sj (x, GMP_RNDN); + if (d != INTMAX_MAX || mpfr_erangeflag_p ()) + { + printf ("ERROR for get_sj + ERANGE + INTMAX_MAX (1)\n"); + exit (1); + } + mpfr_add_ui (x, x, 1, GMP_RNDN); + d = mpfr_get_sj (x, GMP_RNDN); + if (d != INTMAX_MAX || !mpfr_erangeflag_p ()) + { + printf ("ERROR for get_sj + ERANGE + INTMAX_MAX (2)\n"); + exit (1); + } + mpfr_set_sj (x, INTMAX_MIN, GMP_RNDN); + mpfr_clear_erangeflag (); + d = mpfr_get_sj (x, GMP_RNDN); + if (d != INTMAX_MIN || mpfr_erangeflag_p ()) + { + printf ("ERROR for get_sj + ERANGE + INTMAX_MIN (1)\n"); + exit (1); + } + mpfr_sub_ui (x, x, 1, GMP_RNDN); + d = mpfr_get_sj (x, GMP_RNDN); + if (d != INTMAX_MIN || !mpfr_erangeflag_p ()) + { + printf ("ERROR for get_sj + ERANGE + INTMAX_MIN (2)\n"); + exit (1); + } + + mpfr_clear (x); +} + int main (void) { @@ -181,6 +255,8 @@ main (void) mpfr_clear (x); mpfr_clear (y); + check_erange (); + tests_end_mpfr (); return 0; } diff --git a/tests/tset_si.c b/tests/tset_si.c index 342b018d6..9f4771283 100644 --- a/tests/tset_si.c +++ b/tests/tset_si.c @@ -79,7 +79,7 @@ main (int argc, char *argv[]) mpfr_init2 (x, 100); - N = (argc==1) ? 200000 : atol (argv[1]); + N = (argc==1) ? 100000 : atol (argv[1]); for (k = 1; k <= N; k++) { @@ -252,6 +252,62 @@ main (int argc, char *argv[]) MPFR_ASSERTN(mpfr_inf_p (x) && mpfr_sgn (x) > 0); mpfr_set_emax (emax); + /* Test for ERANGE flag + correct behaviour if overflow */ + mpfr_set_prec (x, 256); + mpfr_set_ui (x, ULONG_MAX, GMP_RNDN); + mpfr_clear_erangeflag (); + dl = mpfr_get_ui (x, GMP_RNDN); + if (dl != ULONG_MAX || mpfr_erangeflag_p ()) + { + printf ("ERROR for get_ui + ERANGE + ULONG_MAX (1)\n"); + exit (1); + } + mpfr_add_ui (x, x, 1, GMP_RNDN); + dl = mpfr_get_ui (x, GMP_RNDN); + if (dl != ULONG_MAX || !mpfr_erangeflag_p ()) + { + printf ("ERROR for get_ui + ERANGE + ULONG_MAX (2)\n"); + exit (1); + } + mpfr_set_si (x, -1, GMP_RNDN); + mpfr_clear_erangeflag (); + dl = mpfr_get_ui (x, GMP_RNDN); + if (dl != 0 || !mpfr_erangeflag_p ()) + { + printf ("ERROR for get_ui + ERANGE + -1 \n"); + exit (1); + } + mpfr_set_si (x, LONG_MAX, GMP_RNDN); + mpfr_clear_erangeflag (); + d = mpfr_get_si (x, GMP_RNDN); + if (d != LONG_MAX || mpfr_erangeflag_p ()) + { + printf ("ERROR for get_si + ERANGE + LONG_MAX (1): %ld\n", d); + exit (1); + } + mpfr_add_ui (x, x, 1, GMP_RNDN); + d = mpfr_get_si (x, GMP_RNDN); + if (d != LONG_MAX || !mpfr_erangeflag_p ()) + { + printf ("ERROR for get_si + ERANGE + LONG_MAX (2)\n"); + exit (1); + } + mpfr_set_si (x, LONG_MIN, GMP_RNDN); + mpfr_clear_erangeflag (); + d = mpfr_get_si (x, GMP_RNDN); + if (d != LONG_MIN || mpfr_erangeflag_p ()) + { + printf ("ERROR for get_si + ERANGE + LONG_MIN (1)\n"); + exit (1); + } + mpfr_sub_ui (x, x, 1, GMP_RNDN); + d = mpfr_get_si (x, GMP_RNDN); + if (d != LONG_MIN || !mpfr_erangeflag_p ()) + { + printf ("ERROR for get_si + ERANGE + LONG_MIN (2)\n"); + exit (1); + } + mpfr_clear (x); test_2exp (); diff --git a/tests/tset_sj.c b/tests/tset_sj.c index 4f75f2bcd..c43dbd7c6 100644 --- a/tests/tset_sj.c +++ b/tests/tset_sj.c @@ -28,6 +28,13 @@ MA 02111-1307, USA. */ #include #include +/* The ISO C99 standard specifies that in C++ implementations the + INTMAX_MAX, ... macros should only be defined if explicitly requested. */ +#if defined __cplusplus +# define __STDC_LIMIT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + #ifdef HAVE_STDINT_H # include #endif -- cgit v1.2.1