mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-23 09:43:32 +08:00
More thoroughly test underflow / errno in tst-strtod-round
Add tests of underflow in tst-strtod-round, and thus also test for
errno being unchanged when there is neither overflow nor underflow.
The errno setting before the function call to test for being unchanged
is adjusted to set errno to 12345 instead of 0, so that any bugs where
strtod sets errno to 0 would be detected.
This doesn't add any new test inputs for tst-strtod-round, and in
particular doesn't cover the edge cases of underflow the way
tst-strtod-underflow does (none of the existing test inputs for
tst-strtod-round actually exercise cases that have underflow with
before-rounding tininess detection but not with after-rounding
tininess detection), but at least it provides some coverage (as per
the recent discussions) that ordinary non-overflowing non-underflowing
inputs to these functions do not set errno.
Tested for x86_64.
(cherry picked from commit d73ed2601b
)
This commit is contained in:
parent
9bc76c7ca4
commit
e06153665f
@ -46,6 +46,7 @@ static int
|
||||
string_to_fp (mpfr_t f, const char *s, mpfr_rnd_t rnd)
|
||||
{
|
||||
mpfr_clear_overflow ();
|
||||
mpfr_clear_underflow ();
|
||||
#ifdef WORKAROUND
|
||||
mpfr_t f2;
|
||||
mpfr_init2 (f2, 100000);
|
||||
@ -53,12 +54,16 @@ string_to_fp (mpfr_t f, const char *s, mpfr_rnd_t rnd)
|
||||
int r = mpfr_set (f, f2, rnd);
|
||||
r |= mpfr_subnormalize (f, r, rnd);
|
||||
mpfr_clear (f2);
|
||||
return r0 | r;
|
||||
r |= r0;
|
||||
#else
|
||||
int r = mpfr_strtofr (f, s, NULL, 0, rnd);
|
||||
r |= mpfr_subnormalize (f, r, rnd);
|
||||
return r;
|
||||
#endif
|
||||
if (r == 0)
|
||||
/* The MPFR underflow flag is set for exact subnormal results,
|
||||
which is not wanted here. */
|
||||
mpfr_clear_underflow ();
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
@ -70,6 +75,21 @@ print_fp (FILE *fout, mpfr_t f, const char *suffix)
|
||||
mpfr_fprintf (fout, "\t%Ra%s", f, suffix);
|
||||
}
|
||||
|
||||
static const char *
|
||||
suffix_to_print (bool overflow, bool underflow, bool underflow_before_rounding,
|
||||
bool with_comma)
|
||||
{
|
||||
if (overflow)
|
||||
return with_comma ? ", true, false,\n" : ", true, false";
|
||||
if (underflow)
|
||||
return with_comma ? ", false, true,\n" : ", false, true";
|
||||
if (underflow_before_rounding)
|
||||
return (with_comma
|
||||
? ", false, !TININESS_AFTER_ROUNDING,\n"
|
||||
: ", false, !TININESS_AFTER_ROUNDING");
|
||||
return with_comma ? ", false, false,\n" : ", false, false";
|
||||
}
|
||||
|
||||
static void
|
||||
round_str (FILE *fout, const char *s, int prec, int emin, int emax,
|
||||
bool ibm_ld)
|
||||
@ -80,8 +100,11 @@ round_str (FILE *fout, const char *s, int prec, int emin, int emax,
|
||||
mpfr_set_emin (emin);
|
||||
mpfr_set_emax (emax);
|
||||
mpfr_init (f);
|
||||
string_to_fp (f, s, MPFR_RNDZ);
|
||||
bool underflow_before_rounding = mpfr_underflow_p () != 0;
|
||||
int r = string_to_fp (f, s, MPFR_RNDD);
|
||||
bool overflow = mpfr_overflow_p () != 0;
|
||||
bool underflow = mpfr_underflow_p () != 0;
|
||||
if (ibm_ld)
|
||||
{
|
||||
assert (prec == 106 && emin == -1073 && emax == 1024);
|
||||
@ -97,19 +120,27 @@ round_str (FILE *fout, const char *s, int prec, int emin, int emax,
|
||||
}
|
||||
}
|
||||
mpfr_fprintf (fout, "\t%s,\n", r ? "false" : "true");
|
||||
print_fp (fout, f, overflow ? ", true,\n" : ", false,\n");
|
||||
print_fp (fout, f,
|
||||
suffix_to_print (overflow, underflow, underflow_before_rounding,
|
||||
true));
|
||||
string_to_fp (f, s, MPFR_RNDN);
|
||||
overflow = (mpfr_overflow_p () != 0
|
||||
|| (ibm_ld && mpfr_cmpabs (f, max_value) > 0));
|
||||
print_fp (fout, f, overflow ? ", true,\n" : ", false,\n");
|
||||
print_fp (fout, f,
|
||||
suffix_to_print (overflow, underflow, underflow_before_rounding,
|
||||
true));
|
||||
string_to_fp (f, s, MPFR_RNDZ);
|
||||
overflow = (mpfr_overflow_p () != 0
|
||||
|| (ibm_ld && mpfr_cmpabs (f, max_value) > 0));
|
||||
print_fp (fout, f, overflow ? ", true,\n" : ", false,\n");
|
||||
print_fp (fout, f,
|
||||
suffix_to_print (overflow, underflow, underflow_before_rounding,
|
||||
true));
|
||||
string_to_fp (f, s, MPFR_RNDU);
|
||||
overflow = (mpfr_overflow_p () != 0
|
||||
|| (ibm_ld && mpfr_cmpabs (f, max_value) > 0));
|
||||
print_fp (fout, f, overflow ? ", true" : ", false");
|
||||
print_fp (fout, f,
|
||||
suffix_to_print (overflow, underflow, underflow_before_rounding,
|
||||
false));
|
||||
mpfr_clear (f);
|
||||
if (ibm_ld)
|
||||
mpfr_clear (max_value);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -30,6 +30,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math-tests.h>
|
||||
#include <tininess.h>
|
||||
|
||||
#include "tst-strtod.h"
|
||||
|
||||
@ -139,16 +140,26 @@
|
||||
gen-tst-strtod-round utility to select the appropriately
|
||||
rounded long double value for a given format. */
|
||||
#define TEST(s, \
|
||||
fx, fd, fdo, fn, fno, fz, fzo, fu, fuo, \
|
||||
dx, dd, ddo, dn, dno, dz, dzo, du, duo, \
|
||||
ld64ix, ld64id, ld64ido, ld64in, ld64ino, \
|
||||
ld64iz, ld64izo, ld64iu, ld64iuo, \
|
||||
ld64mx, ld64md, ld64mdo, ld64mn, ld64mno, \
|
||||
ld64mz, ld64mzo, ld64mu, ld64muo, \
|
||||
ld106x, ld106d, ld106do, ld106n, ld106no, \
|
||||
ld106z, ld106zo, ld106u, ld106uo, \
|
||||
ld113x, ld113d, ld113do, ld113n, ld113no, \
|
||||
ld113z, ld113zo, ld113u, ld113uo) \
|
||||
fx, fd, fdo, fdu, fn, fno, fnu, \
|
||||
fz, fzo, fzu, fu, fuo, fuu, \
|
||||
dx, dd, ddo, ddu, dn, dno, dnu, \
|
||||
dz, dzo, dzu, du, duo, duu, \
|
||||
ld64ix, ld64id, ld64ido, ld64idu, \
|
||||
ld64in, ld64ino, ld64inu, \
|
||||
ld64iz, ld64izo, ld64izu, \
|
||||
ld64iu, ld64iuo, ld64iuu, \
|
||||
ld64mx, ld64md, ld64mdo, ld64mdu, \
|
||||
ld64mn, ld64mno, ld64mnu, \
|
||||
ld64mz, ld64mzo, ld64mzu, \
|
||||
ld64mu, ld64muo, ld64muu, \
|
||||
ld106x, ld106d, ld106do, ld106du, \
|
||||
ld106n, ld106no, ld106nu, \
|
||||
ld106z, ld106zo, ld106zu, \
|
||||
ld106u, ld106uo, ld106uu, \
|
||||
ld113x, ld113d, ld113do, ld113du, \
|
||||
ld113n, ld113no, ld113nu, \
|
||||
ld113z, ld113zo, ld113zu, \
|
||||
ld113u, ld113uo, ld113uu) \
|
||||
{ \
|
||||
L_ (s), \
|
||||
{ XNTRY (fx, dx, ld64ix, ld64mx, ld106x, ld113x) }, \
|
||||
@ -163,6 +174,12 @@
|
||||
{ XNTRY (fdo, ddo, ld64ido, ld64mdo, ld106do, ld113do) }, \
|
||||
{ XNTRY (fzo, dzo, ld64izo, ld64mzo, ld106zo, ld113zo) }, \
|
||||
{ XNTRY (fuo, duo, ld64iuo, ld64muo, ld106uo, ld113uo) } \
|
||||
}, \
|
||||
{ \
|
||||
{ XNTRY (fnu, dnu, ld64inu, ld64mnu, ld106nu, ld113nu) }, \
|
||||
{ XNTRY (fdu, ddu, ld64idu, ld64mdu, ld106du, ld113du) }, \
|
||||
{ XNTRY (fzu, dzu, ld64izu, ld64mzu, ld106zu, ld113zu) }, \
|
||||
{ XNTRY (fuu, duu, ld64iuu, ld64muu, ld106uu, ld113uu) } \
|
||||
} \
|
||||
}
|
||||
|
||||
@ -181,11 +198,17 @@ struct test_overflow
|
||||
STRUCT_FOREACH_FLOAT_BOOL
|
||||
};
|
||||
|
||||
struct test_underflow
|
||||
{
|
||||
STRUCT_FOREACH_FLOAT_BOOL
|
||||
};
|
||||
|
||||
struct test {
|
||||
const CHAR *s;
|
||||
struct test_exactness exact;
|
||||
struct test_results r[4];
|
||||
struct test_overflow o[4];
|
||||
struct test_underflow u[4];
|
||||
};
|
||||
|
||||
/* Include the generated test data. */
|
||||
@ -203,10 +226,14 @@ struct test {
|
||||
# define FE_OVERFLOW 0
|
||||
#endif
|
||||
|
||||
#ifndef FE_UNDERFLOW
|
||||
# define FE_UNDERFLOW 0
|
||||
#endif
|
||||
|
||||
#define GEN_ONE_TEST(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
|
||||
{ \
|
||||
feclearexcept (FE_ALL_EXCEPT); \
|
||||
errno = 0; \
|
||||
errno = 12345; \
|
||||
FTYPE f = STRTO (FSUF) (s, NULL); \
|
||||
int new_errno = errno; \
|
||||
if (f != expected->FSUF \
|
||||
@ -265,6 +292,40 @@ struct test {
|
||||
s, new_errno, ERANGE); \
|
||||
result = 1; \
|
||||
} \
|
||||
if (FE_UNDERFLOW != 0) \
|
||||
{ \
|
||||
bool underflow_raised \
|
||||
= fetestexcept (FE_UNDERFLOW) != 0; \
|
||||
if (underflow_raised != underflow->FSUF) \
|
||||
{ \
|
||||
printf (FNPFXS "to" #FSUF \
|
||||
" (" STRM ") underflow %d " \
|
||||
"not %d\n", s, underflow_raised, \
|
||||
underflow->FSUF); \
|
||||
if (EXCEPTION_TESTS (FTYPE)) \
|
||||
result = 1; \
|
||||
else \
|
||||
printf ("ignoring this exception error\n"); \
|
||||
} \
|
||||
} \
|
||||
if (underflow->FSUF && new_errno != ERANGE) \
|
||||
{ \
|
||||
printf (FNPFXS "to" #FSUF \
|
||||
" (" STRM ") left errno == %d," \
|
||||
" not %d (ERANGE)\n", \
|
||||
s, new_errno, ERANGE); \
|
||||
result = 1; \
|
||||
} \
|
||||
if (!overflow->FSUF \
|
||||
&& !underflow->FSUF \
|
||||
&& new_errno != 12345) \
|
||||
{ \
|
||||
printf (FNPFXS "to" #FSUF \
|
||||
" (" STRM ") set errno == %d," \
|
||||
" should be unchanged\n", \
|
||||
s, new_errno); \
|
||||
result = 1; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
@ -272,6 +333,7 @@ static int
|
||||
test_in_one_mode (const CHAR *s, const struct test_results *expected,
|
||||
const struct test_exactness *exact,
|
||||
const struct test_overflow *overflow,
|
||||
const struct test_underflow *underflow,
|
||||
const char *mode_name, int rnd_mode)
|
||||
{
|
||||
int result = 0;
|
||||
@ -307,6 +369,7 @@ do_test (void)
|
||||
{
|
||||
result |= test_in_one_mode (tests[i].s, &tests[i].r[modes[0].rnd_i],
|
||||
&tests[i].exact, &tests[i].o[modes[0].rnd_i],
|
||||
&tests[i].u[modes[0].rnd_i],
|
||||
modes[0].mode_name, modes[0].rnd_mode);
|
||||
for (const struct fetestmodes *m = &modes[1]; m->mode_name != NULL; m++)
|
||||
{
|
||||
@ -314,7 +377,9 @@ do_test (void)
|
||||
{
|
||||
result |= test_in_one_mode (tests[i].s, &tests[i].r[m->rnd_i],
|
||||
&tests[i].exact,
|
||||
&tests[i].o[m->rnd_i], m->mode_name,
|
||||
&tests[i].o[m->rnd_i],
|
||||
&tests[i].u[m->rnd_i],
|
||||
m->mode_name,
|
||||
m->rnd_mode);
|
||||
fesetround (save_round_mode);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user