change arf_get_mpfr to return an MPFR underflow/overflow result instead of throwing flint_abort() if the exponent is out of bounds

This commit is contained in:
fredrik 2020-03-30 12:34:08 +02:00
parent 58d9ef888d
commit f433b7597e
4 changed files with 131 additions and 4 deletions

View file

@ -30,9 +30,49 @@ arf_get_mpfr(mpfr_t x, const arf_t y, mpfr_rnd_t rnd)
}
else if (COEFF_IS_MPZ(*ARF_EXPREF(y)))
{
flint_printf("exception: exponent too large to convert to mpfr");
flint_abort();
r = 0; /* dummy return because flint_abort() is not declared noreturn */
/* Incidentally, COEFF_MIN and COEFF_MAX are exactly the same
as the minimum and maximum allowed MPFR exponents. We
assert this to make sure the following code is valid.
Unfortunately, MPFR provides no convenient function to
assign a big exponent with automatic underflow/overflow. */
if (COEFF_MIN > mpfr_get_emin_min() ||
COEFF_MAX < mpfr_get_emax_max())
{
flint_printf("unsupported MPFR exponent range: %wd, %wd, %wd, %wd\n",
COEFF_MIN, mpfr_get_emin_min(), COEFF_MAX, mpfr_get_emax_max());
flint_abort();
}
if (fmpz_sgn(ARF_EXPREF(y)) > 0)
{
if (arf_sgn(y) > 0)
{
mpfr_set_inf(x, 1);
mpfr_nextbelow(x);
}
else
{
mpfr_set_inf(x, -1);
mpfr_nextabove(x);
}
r = mpfr_mul_2si(x, x, 1, rnd);
}
else
{
if (arf_sgn(y) > 0)
{
mpfr_set_zero(x, 1);
mpfr_nextabove(x);
}
else
{
mpfr_set_zero(x, -1);
mpfr_nextbelow(x);
}
r = mpfr_mul_2si(x, x, -1, rnd);
}
}
else
{

View file

@ -46,6 +46,7 @@ int main()
{
arf_t x, y, z;
int conversion_error;
FILE* tmp;
arf_init(x);
arf_init(y);
@ -55,7 +56,7 @@ int main()
arf_randtest_special(y, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100));
arf_randtest_special(z, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100));
FILE* tmp = tmpfile();
tmp = tmpfile();
arf_dump_file(tmp, x);
fputc(' ', tmp);
arf_dump_file(tmp, y);

View file

@ -50,6 +50,88 @@ int main()
mpfr_clear(y);
}
/* test set_mpfr out of range */
{
arf_t x, z;
mpfr_t y;
fmpz_t e;
int r;
fmpz_init(e);
arf_init(x);
arf_init(z);
mpfr_init2(y, 53);
fmpz_one(e);
fmpz_mul_2exp(e, e, 100);
arf_set_si(x, 1);
arf_mul_2exp_fmpz(x, x, e);
r = arf_get_mpfr(y, x, MPFR_RNDN);
arf_set_mpfr(x, y);
if (!mpfr_inf_p(y) || mpfr_sgn(y) <= 0 || !mpfr_overflow_p())
{
flint_printf("expected +inf with overflow\n\n");
arf_print(z); flint_printf("\n\n");
flint_printf("r = %d \n\n", r);
flint_abort();
}
mpfr_clear_flags();
arf_set_si(x, -1);
arf_mul_2exp_fmpz(x, x, e);
r = arf_get_mpfr(y, x, MPFR_RNDN);
arf_set_mpfr(x, y);
if (!mpfr_inf_p(y) || mpfr_sgn(y) >= 0 || !mpfr_overflow_p())
{
flint_printf("expected -inf with overflow\n\n");
arf_print(z); flint_printf("\n\n");
flint_printf("r = %d \n\n", r);
flint_abort();
}
mpfr_clear_flags();
fmpz_neg(e, e);
arf_set_si(x, 1);
arf_mul_2exp_fmpz(x, x, e);
r = arf_get_mpfr(y, x, MPFR_RNDN);
arf_set_mpfr(x, y);
if (!mpfr_zero_p(y) || mpfr_signbit(y) || !mpfr_underflow_p())
{
flint_printf("expected +0 with underflow\n\n");
arf_print(z); flint_printf("\n\n");
flint_printf("r = %d \n\n", r);
flint_abort();
}
mpfr_clear_flags();
arf_set_si(x, -1);
arf_mul_2exp_fmpz(x, x, e);
r = arf_get_mpfr(y, x, MPFR_RNDN);
arf_set_mpfr(x, y);
if (!mpfr_zero_p(y) || !mpfr_signbit(y) || !mpfr_underflow_p())
{
flint_printf("expected -0 with underflow\n\n");
arf_print(z); flint_printf("\n\n");
flint_printf("r = %d \n\n", r);
flint_abort();
}
mpfr_clear_flags();
arf_clear(x);
arf_clear(z);
mpfr_clear(y);
fmpz_clear(e);
}
flint_randclear(state);
flint_cleanup();
flint_printf("PASS\n");

View file

@ -267,6 +267,10 @@ Assignment, rounding and conversions
indicates the direction of rounding, following the convention
of the MPFR library.
If *x* has an exponent too large or small to fit in the MPFR type, the
result overflows to an infinity or underflows to a (signed) zero,
and the corresponding MPFR exception flags are set.
.. function:: int arf_get_fmpz(fmpz_t res, const arf_t x, arf_rnd_t rnd)
Sets *res* to *x* rounded to the nearest integer in the direction