diff options
-rw-r--r-- | get_si.c | 10 | ||||
-rw-r--r-- | get_sj.c | 9 | ||||
-rw-r--r-- | get_ui.c | 8 | ||||
-rw-r--r-- | get_uj.c | 5 | ||||
-rw-r--r-- | get_z.c | 18 | ||||
-rw-r--r-- | get_z_exp.c | 22 | ||||
-rw-r--r-- | mpfr.texi | 20 | ||||
-rw-r--r-- | tests/tget_sj.c | 16 | ||||
-rw-r--r-- | tests/tget_z.c | 40 | ||||
-rw-r--r-- | tests/tset_si.c | 16 |
10 files changed, 131 insertions, 33 deletions
@@ -32,14 +32,16 @@ mpfr_get_si (mpfr_srcptr f, mpfr_rnd_t rnd) if (MPFR_UNLIKELY (!mpfr_fits_slong_p (f, rnd))) { MPFR_SET_ERANGE (); - return MPFR_IS_NEG (f) ? LONG_MIN : LONG_MAX; + return MPFR_IS_NAN (f) ? 0 : + MPFR_IS_NEG (f) ? LONG_MIN : LONG_MAX; } - else if (MPFR_UNLIKELY (MPFR_IS_ZERO (f))) - return (long) 0; + if (MPFR_IS_ZERO (f)) + return (long) 0; /* determine prec of long */ - for (s = LONG_MIN, prec = 0; s != 0; s /= 2, prec ++); + for (s = LONG_MIN, prec = 0; s != 0; s /= 2, prec++) + { } /* first round to prec bits */ mpfr_init2 (x, prec); @@ -50,18 +50,19 @@ mpfr_get_sj (mpfr_srcptr f, mpfr_rnd_t rnd) mpfr_prec_t prec; mpfr_t x; - if (!mpfr_fits_intmax_p (f, rnd)) + if (MPFR_UNLIKELY (!mpfr_fits_intmax_p (f, rnd))) { MPFR_SET_ERANGE (); - return MPFR_IS_NEG (f) ? MPFR_INTMAX_MIN : MPFR_INTMAX_MAX; + return MPFR_IS_NAN (f) ? 0 : + MPFR_IS_NEG (f) ? MPFR_INTMAX_MIN : MPFR_INTMAX_MAX; } + if (MPFR_IS_ZERO (f)) return (intmax_t) 0; /* determine the precision of intmax_t */ for (r = MPFR_INTMAX_MIN, prec = 0; r != 0; r /= 2, prec++) - { - } + { } /* Note: though INTMAX_MAX would have been sufficient for the conversion, we chose INTMAX_MIN so that INTMAX_MIN - 1 is always representable in precision prec; this is useful to detect overflows in MPFR_RNDZ (will @@ -31,16 +31,18 @@ mpfr_get_ui (mpfr_srcptr f, mpfr_rnd_t rnd) mp_size_t n; mpfr_exp_t exp; - if (!mpfr_fits_ulong_p (f, rnd)) + if (MPFR_UNLIKELY (!mpfr_fits_ulong_p (f, rnd))) { MPFR_SET_ERANGE (); - return MPFR_IS_NEG (f) ? 0 : ULONG_MAX; + return MPFR_IS_NAN (f) || MPFR_IS_NEG (f) ? + (unsigned long) 0 : ULONG_MAX; } if (MPFR_IS_ZERO (f)) return (unsigned long) 0; - for (s = ULONG_MAX, prec = 0; s != 0; s >>= 1, prec ++); + for (s = ULONG_MAX, prec = 0; s != 0; s /= 2, prec ++) + { } /* first round to prec bits */ mpfr_init2 (x, prec); @@ -50,10 +50,11 @@ mpfr_get_uj (mpfr_srcptr f, mpfr_rnd_t rnd) mpfr_prec_t prec; mpfr_t x; - if (!mpfr_fits_uintmax_p (f, rnd)) + if (MPFR_UNLIKELY (!mpfr_fits_uintmax_p (f, rnd))) { MPFR_SET_ERANGE (); - return MPFR_IS_NEG (f) ? (uintmax_t) 0 : MPFR_UINTMAX_MAX; + return MPFR_IS_NAN (f) || MPFR_IS_NEG (f) ? + (uintmax_t) 0 : MPFR_UINTMAX_MAX; } if (MPFR_IS_ZERO (f)) @@ -28,8 +28,20 @@ mpfr_get_z (mpz_ptr z, mpfr_srcptr f, mpfr_rnd_t rnd) { int inex; mpfr_t r; - mpfr_exp_t exp = MPFR_EXP (f); - + mpfr_exp_t exp; + + if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (f))) + { + if (MPFR_UNLIKELY (MPFR_NOTZERO (f))) + MPFR_SET_ERANGE (); + mpz_set_ui (z, 0); + /* The ternary value is 0 even for infinity. Giving the rounding + direction in this case would not make much sense anyway, and + the direction would not necessarily match rnd. */ + return 0; + } + + exp = MPFR_GET_EXP (f); /* if exp <= 0, then |f|<1, thus |o(f)|<=1 */ MPFR_ASSERTN (exp < 0 || exp <= MPFR_PREC_MAX); mpfr_init2 (r, (exp < (mpfr_exp_t) MPFR_PREC_MIN ? @@ -37,7 +49,7 @@ mpfr_get_z (mpz_ptr z, mpfr_srcptr f, mpfr_rnd_t rnd) inex = mpfr_rint (r, f, rnd); MPFR_ASSERTN (inex != 1 && inex != -1); /* integral part of f is representable in r */ - MPFR_ASSERTN (MPFR_IS_FP (r) ); + MPFR_ASSERTN (MPFR_IS_FP (r)); exp = mpfr_get_z_2exp (z, r); if (exp >= 0) mpz_mul_2exp (z, z, exp); diff --git a/get_z_exp.c b/get_z_exp.c index 7d1cbd250..7cb34f900 100644 --- a/get_z_exp.c +++ b/get_z_exp.c @@ -33,6 +33,10 @@ http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., * on nonnegative numbers. --> This is WRONG since the returned * exponent is not necessarily in the exponent range! * Note that this is different from the C function frexp(). + * + * For NaN and infinities, we choose to set z = 0 (neutral value). + * The exponent doesn't really matter, so let's keep __gmpfr_emin + * for consistency. The erange flag is set. */ mpfr_exp_t @@ -41,10 +45,10 @@ mpfr_get_z_2exp (mpz_ptr z, mpfr_srcptr f) mp_size_t fn; int sh; - MPFR_ASSERTD (MPFR_IS_FP (f)); - - if (MPFR_UNLIKELY (MPFR_IS_ZERO (f))) + if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (f))) { + if (MPFR_UNLIKELY (MPFR_NOTZERO (f))) + MPFR_SET_ERANGE (); mpz_set_ui (z, 0); return __gmpfr_emin; } @@ -63,11 +67,13 @@ mpfr_get_z_2exp (mpz_ptr z, mpfr_srcptr f) SIZ(z) = MPFR_IS_NEG (f) ? -fn : fn; - /* Test if the result is representable. Later, we could choose - to return MPFR_EXP_MIN if it isn't, or perhaps MPFR_EXP_MAX - to signal an error. The significand would still be meaningful. */ - MPFR_ASSERTD ((mpfr_uexp_t) MPFR_GET_EXP (f) - MPFR_EXP_MIN - >= (mpfr_uexp_t) MPFR_PREC(f)); + if (MPFR_UNLIKELY ((mpfr_uexp_t) MPFR_GET_EXP (f) - MPFR_EXP_MIN + < (mpfr_uexp_t) MPFR_PREC (f))) + { + /* The exponent isn't representable in an mpfr_exp_t. */ + MPFR_SET_ERANGE (); + return MPFR_EXP_MIN; + } return MPFR_GET_EXP (f) - MPFR_PREC (f); } @@ -1278,13 +1278,10 @@ see the documentation of @code{mpfr_set_decimal64}. Convert @var{op} to a @code{long}, an @code{unsigned long}, an @code{intmax_t} or an @code{uintmax_t} (respectively) after rounding it with respect to @var{rnd}. -If @var{op} is NaN, the result is undefined. -@c PZ: is the erange flag set in the above case? -@c VL: no, however we could decide to set it and return an arbitrary value, -@c e.g. 0. -If @var{op} is too big for the return type, it returns the maximum +If @var{op} is NaN, 0 is returned and the @emph{erange} flag is set. +If @var{op} is too big for the return type, the function returns the maximum or the minimum of the corresponding C type, depending on the direction -of the overflow. The @emph{erange} flag is set too. +of the overflow; the @emph{erange} flag is set too. See also @code{mpfr_fits_slong_p}, @code{mpfr_fits_ulong_p}, @code{mpfr_fits_intmax_p} and @code{mpfr_fits_uintmax_p}. @end deftypefun @@ -1318,13 +1315,18 @@ exactly equals $rop \times 2^{\rm exp}$. @end tex If @var{op} is zero, the minimal exponent @code{emin} is returned. -If the exponent is not representable in the @code{mpfr_exp_t} type, the -behavior is undefined. +If @var{op} is NaN or an infinity, the @emph{erange} flag is set, @var{rop} +is set to 0, and the the minimal exponent @code{emin} is returned. +The returned exponent may be less than the minimal exponent @code{emin} +of MPFR numbers in the current exponent range; in case the exponent is +not representable in the @code{mpfr_exp_t} type, the @emph{erange} flag +is set and the minimal value of the @code{mpfr_exp_t} type is returned. @end deftypefun @deftypefun int mpfr_get_z (mpz_t @var{rop}, mpfr_t @var{op}, mpfr_rnd_t @var{rnd}) Convert @var{op} to a @code{mpz_t}, after rounding it with respect to -@var{rnd}. If @var{op} is NaN or Inf, the result is undefined. +@var{rnd}. If @var{op} is NaN or n infinity, the @emph{erange} flag is +set, @var{rop} is set to 0, and 0 is returned. @end deftypefun @deftypefun int mpfr_get_f (mpf_t @var{rop}, mpfr_t @var{op}, mpfr_rnd_t @var{rnd}) diff --git a/tests/tget_sj.c b/tests/tget_sj.c index 0d07c34d2..e733aa052 100644 --- a/tests/tget_sj.c +++ b/tests/tget_sj.c @@ -205,6 +205,22 @@ check_erange (void) exit (1); } + mpfr_set_nan (x); + mpfr_clear_erangeflag (); + d = mpfr_get_uj (x, MPFR_RNDN); + if (d != 0 || !mpfr_erangeflag_p ()) + { + printf ("ERROR for get_uj + NaN\n"); + exit (1); + } + mpfr_clear_erangeflag (); + d = mpfr_get_sj (x, MPFR_RNDN); + if (d != 0 || !mpfr_erangeflag_p ()) + { + printf ("ERROR for get_sj + NaN\n"); + exit (1); + } + mpfr_clear (x); } diff --git a/tests/tget_z.c b/tests/tget_z.c index 887d624be..a8be3d59b 100644 --- a/tests/tget_z.c +++ b/tests/tget_z.c @@ -148,6 +148,45 @@ check (void) mpz_clear (z); } +static void +special (void) +{ + int inex; + mpfr_t x; + mpz_t z; + int i; + mpfr_exp_t e; + + mpfr_init2 (x, 2); + mpz_init (z); + + for (i = -1; i <= 1; i++) + { + if (i != 0) + mpfr_set_nan (x); + else + mpfr_set_inf (x, i); + mpfr_clear_flags (); + inex = mpfr_get_z (z, x, MPFR_RNDN); + if (!mpfr_erangeflag_p () || inex != 0 || mpz_cmp_ui (z, 0) != 0) + { + printf ("special() failed on mpfr_get_z for i = %d\n", i); + exit (1); + } + mpfr_clear_flags (); + e = mpfr_get_z_2exp (z, x); + if (!mpfr_erangeflag_p () || e != __gmpfr_emin || + mpz_cmp_ui (z, 0) != 0) + { + printf ("special() failed on mpfr_get_z_2exp for i = %d\n", i); + exit (1); + } + } + + mpfr_clear (x); + mpz_clear (z); +} + int main (void) { @@ -155,6 +194,7 @@ main (void) check (); check_diff (); + special (); tests_end_mpfr (); return 0; diff --git a/tests/tset_si.c b/tests/tset_si.c index 5f0872e22..22eb6c44b 100644 --- a/tests/tset_si.c +++ b/tests/tset_si.c @@ -372,6 +372,22 @@ main (int argc, char *argv[]) exit (1); } + mpfr_set_nan (x); + mpfr_clear_erangeflag (); + d = mpfr_get_ui (x, MPFR_RNDN); + if (d != 0 || !mpfr_erangeflag_p ()) + { + printf ("ERROR for get_ui + NaN\n"); + exit (1); + } + mpfr_clear_erangeflag (); + d = mpfr_get_si (x, MPFR_RNDN); + if (d != 0 || !mpfr_erangeflag_p ()) + { + printf ("ERROR for get_si + NaN\n"); + exit (1); + } + emin = mpfr_get_emin (); mpfr_set_prec (x, 2); |