mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 20:40:05 +00: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.
This commit is contained in:
parent
3de73f974f
commit
d73ed2601b
@ -46,6 +46,7 @@ static int
|
|||||||
string_to_fp (mpfr_t f, const char *s, mpfr_rnd_t rnd)
|
string_to_fp (mpfr_t f, const char *s, mpfr_rnd_t rnd)
|
||||||
{
|
{
|
||||||
mpfr_clear_overflow ();
|
mpfr_clear_overflow ();
|
||||||
|
mpfr_clear_underflow ();
|
||||||
#ifdef WORKAROUND
|
#ifdef WORKAROUND
|
||||||
mpfr_t f2;
|
mpfr_t f2;
|
||||||
mpfr_init2 (f2, 100000);
|
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);
|
int r = mpfr_set (f, f2, rnd);
|
||||||
r |= mpfr_subnormalize (f, r, rnd);
|
r |= mpfr_subnormalize (f, r, rnd);
|
||||||
mpfr_clear (f2);
|
mpfr_clear (f2);
|
||||||
return r0 | r;
|
r |= r0;
|
||||||
#else
|
#else
|
||||||
int r = mpfr_strtofr (f, s, NULL, 0, rnd);
|
int r = mpfr_strtofr (f, s, NULL, 0, rnd);
|
||||||
r |= mpfr_subnormalize (f, r, rnd);
|
r |= mpfr_subnormalize (f, r, rnd);
|
||||||
return r;
|
|
||||||
#endif
|
#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
|
void
|
||||||
@ -70,6 +75,21 @@ print_fp (FILE *fout, mpfr_t f, const char *suffix)
|
|||||||
mpfr_fprintf (fout, "\t%Ra%s", f, 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
|
static void
|
||||||
round_str (FILE *fout, const char *s, int prec, int emin, int emax,
|
round_str (FILE *fout, const char *s, int prec, int emin, int emax,
|
||||||
bool ibm_ld)
|
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_emin (emin);
|
||||||
mpfr_set_emax (emax);
|
mpfr_set_emax (emax);
|
||||||
mpfr_init (f);
|
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);
|
int r = string_to_fp (f, s, MPFR_RNDD);
|
||||||
bool overflow = mpfr_overflow_p () != 0;
|
bool overflow = mpfr_overflow_p () != 0;
|
||||||
|
bool underflow = mpfr_underflow_p () != 0;
|
||||||
if (ibm_ld)
|
if (ibm_ld)
|
||||||
{
|
{
|
||||||
assert (prec == 106 && emin == -1073 && emax == 1024);
|
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");
|
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);
|
string_to_fp (f, s, MPFR_RNDN);
|
||||||
overflow = (mpfr_overflow_p () != 0
|
overflow = (mpfr_overflow_p () != 0
|
||||||
|| (ibm_ld && mpfr_cmpabs (f, max_value) > 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);
|
string_to_fp (f, s, MPFR_RNDZ);
|
||||||
overflow = (mpfr_overflow_p () != 0
|
overflow = (mpfr_overflow_p () != 0
|
||||||
|| (ibm_ld && mpfr_cmpabs (f, max_value) > 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);
|
string_to_fp (f, s, MPFR_RNDU);
|
||||||
overflow = (mpfr_overflow_p () != 0
|
overflow = (mpfr_overflow_p () != 0
|
||||||
|| (ibm_ld && mpfr_cmpabs (f, max_value) > 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);
|
mpfr_clear (f);
|
||||||
if (ibm_ld)
|
if (ibm_ld)
|
||||||
mpfr_clear (max_value);
|
mpfr_clear (max_value);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -30,6 +30,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math-tests.h>
|
#include <math-tests.h>
|
||||||
|
#include <tininess.h>
|
||||||
|
|
||||||
#include "tst-strtod.h"
|
#include "tst-strtod.h"
|
||||||
|
|
||||||
@ -139,16 +140,26 @@
|
|||||||
gen-tst-strtod-round utility to select the appropriately
|
gen-tst-strtod-round utility to select the appropriately
|
||||||
rounded long double value for a given format. */
|
rounded long double value for a given format. */
|
||||||
#define TEST(s, \
|
#define TEST(s, \
|
||||||
fx, fd, fdo, fn, fno, fz, fzo, fu, fuo, \
|
fx, fd, fdo, fdu, fn, fno, fnu, \
|
||||||
dx, dd, ddo, dn, dno, dz, dzo, du, duo, \
|
fz, fzo, fzu, fu, fuo, fuu, \
|
||||||
ld64ix, ld64id, ld64ido, ld64in, ld64ino, \
|
dx, dd, ddo, ddu, dn, dno, dnu, \
|
||||||
ld64iz, ld64izo, ld64iu, ld64iuo, \
|
dz, dzo, dzu, du, duo, duu, \
|
||||||
ld64mx, ld64md, ld64mdo, ld64mn, ld64mno, \
|
ld64ix, ld64id, ld64ido, ld64idu, \
|
||||||
ld64mz, ld64mzo, ld64mu, ld64muo, \
|
ld64in, ld64ino, ld64inu, \
|
||||||
ld106x, ld106d, ld106do, ld106n, ld106no, \
|
ld64iz, ld64izo, ld64izu, \
|
||||||
ld106z, ld106zo, ld106u, ld106uo, \
|
ld64iu, ld64iuo, ld64iuu, \
|
||||||
ld113x, ld113d, ld113do, ld113n, ld113no, \
|
ld64mx, ld64md, ld64mdo, ld64mdu, \
|
||||||
ld113z, ld113zo, ld113u, ld113uo) \
|
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), \
|
L_ (s), \
|
||||||
{ XNTRY (fx, dx, ld64ix, ld64mx, ld106x, ld113x) }, \
|
{ XNTRY (fx, dx, ld64ix, ld64mx, ld106x, ld113x) }, \
|
||||||
@ -163,6 +174,12 @@
|
|||||||
{ XNTRY (fdo, ddo, ld64ido, ld64mdo, ld106do, ld113do) }, \
|
{ XNTRY (fdo, ddo, ld64ido, ld64mdo, ld106do, ld113do) }, \
|
||||||
{ XNTRY (fzo, dzo, ld64izo, ld64mzo, ld106zo, ld113zo) }, \
|
{ XNTRY (fzo, dzo, ld64izo, ld64mzo, ld106zo, ld113zo) }, \
|
||||||
{ XNTRY (fuo, duo, ld64iuo, ld64muo, ld106uo, ld113uo) } \
|
{ 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_FOREACH_FLOAT_BOOL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct test_underflow
|
||||||
|
{
|
||||||
|
STRUCT_FOREACH_FLOAT_BOOL
|
||||||
|
};
|
||||||
|
|
||||||
struct test {
|
struct test {
|
||||||
const CHAR *s;
|
const CHAR *s;
|
||||||
struct test_exactness exact;
|
struct test_exactness exact;
|
||||||
struct test_results r[4];
|
struct test_results r[4];
|
||||||
struct test_overflow o[4];
|
struct test_overflow o[4];
|
||||||
|
struct test_underflow u[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Include the generated test data. */
|
/* Include the generated test data. */
|
||||||
@ -203,10 +226,14 @@ struct test {
|
|||||||
# define FE_OVERFLOW 0
|
# define FE_OVERFLOW 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef FE_UNDERFLOW
|
||||||
|
# define FE_UNDERFLOW 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#define GEN_ONE_TEST(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
|
#define GEN_ONE_TEST(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
|
||||||
{ \
|
{ \
|
||||||
feclearexcept (FE_ALL_EXCEPT); \
|
feclearexcept (FE_ALL_EXCEPT); \
|
||||||
errno = 0; \
|
errno = 12345; \
|
||||||
FTYPE f = STRTO (FSUF) (s, NULL); \
|
FTYPE f = STRTO (FSUF) (s, NULL); \
|
||||||
int new_errno = errno; \
|
int new_errno = errno; \
|
||||||
if (f != expected->FSUF \
|
if (f != expected->FSUF \
|
||||||
@ -265,6 +292,40 @@ struct test {
|
|||||||
s, new_errno, ERANGE); \
|
s, new_errno, ERANGE); \
|
||||||
result = 1; \
|
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,
|
test_in_one_mode (const CHAR *s, const struct test_results *expected,
|
||||||
const struct test_exactness *exact,
|
const struct test_exactness *exact,
|
||||||
const struct test_overflow *overflow,
|
const struct test_overflow *overflow,
|
||||||
|
const struct test_underflow *underflow,
|
||||||
const char *mode_name, int rnd_mode)
|
const char *mode_name, int rnd_mode)
|
||||||
{
|
{
|
||||||
int result = 0;
|
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],
|
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].exact, &tests[i].o[modes[0].rnd_i],
|
||||||
|
&tests[i].u[modes[0].rnd_i],
|
||||||
modes[0].mode_name, modes[0].rnd_mode);
|
modes[0].mode_name, modes[0].rnd_mode);
|
||||||
for (const struct fetestmodes *m = &modes[1]; m->mode_name != NULL; m++)
|
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],
|
result |= test_in_one_mode (tests[i].s, &tests[i].r[m->rnd_i],
|
||||||
&tests[i].exact,
|
&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);
|
m->rnd_mode);
|
||||||
fesetround (save_round_mode);
|
fesetround (save_round_mode);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user