summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--get_si.c10
-rw-r--r--get_sj.c9
-rw-r--r--get_ui.c8
-rw-r--r--get_uj.c5
-rw-r--r--get_z.c18
-rw-r--r--get_z_exp.c22
-rw-r--r--mpfr.texi20
-rw-r--r--tests/tget_sj.c16
-rw-r--r--tests/tget_z.c40
-rw-r--r--tests/tset_si.c16
10 files changed, 131 insertions, 33 deletions
diff --git a/get_si.c b/get_si.c
index 83a42eb77..f207ea559 100644
--- a/get_si.c
+++ b/get_si.c
@@ -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);
diff --git a/get_sj.c b/get_sj.c
index 8b5e9f9c8..36f4f6985 100644
--- a/get_sj.c
+++ b/get_sj.c
@@ -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
diff --git a/get_ui.c b/get_ui.c
index c93b34812..9612b2bae 100644
--- a/get_ui.c
+++ b/get_ui.c
@@ -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);
diff --git a/get_uj.c b/get_uj.c
index 3e4cf7ef4..80f1c64ce 100644
--- a/get_uj.c
+++ b/get_uj.c
@@ -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))
diff --git a/get_z.c b/get_z.c
index 5fe2cfe63..f17de56d2 100644
--- a/get_z.c
+++ b/get_z.c
@@ -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);
}
diff --git a/mpfr.texi b/mpfr.texi
index 75a600e58..ae4be81aa 100644
--- a/mpfr.texi
+++ b/mpfr.texi
@@ -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);