From: Joseph Myers Date: Fri, 28 Oct 2016 00:40:23 +0000 (+0000) Subject: Make strtod raise "inexact" exceptions (bug 19380). X-Git-Tag: glibc-2.25~372 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4725d33eed118d69b8110285f7741cde9ddc8b4f;p=thirdparty%2Fglibc.git Make strtod raise "inexact" exceptions (bug 19380). The strtod function should raise the "inexact" exception when its result is inexact, but fails to do so except in the case of underflow or overflow. This patch fixes it to do so for all inexact results. tst-strtod-round is extended to test for this exception; the generator is fixed to properly mark inexact results as such in the case where the inexactness is from the mpfr_subnormalize step. Tested for x86_64, x86 and powerpc. [BZ #19380] * stdlib/strtod_l.c (round_and_return): Force "inexact" exception for inexact results. * stdlib/gen-tst-strtod-round.c (string_to_fp): Return indication of inexact result where mpfr_subnormalize is the only inexact step. * stdlib/tst-strtod-round-data.h: Regenerated. * stdlib/tst-strtod-round-skeleton.c [!FE_INEXACT] (FE_INEXACT): Define to 0. (GEN_ONE_TEST): Test inexact exceptions raised are as expected. --- diff --git a/ChangeLog b/ChangeLog index 8b7b3e43cc4..e1f32df616c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2016-10-28 Joseph Myers + + [BZ #19380] + * stdlib/strtod_l.c (round_and_return): Force "inexact" exception + for inexact results. + * stdlib/gen-tst-strtod-round.c (string_to_fp): Return indication + of inexact result where mpfr_subnormalize is the only inexact + step. + * stdlib/tst-strtod-round-data.h: Regenerated. + * stdlib/tst-strtod-round-skeleton.c [!FE_INEXACT] (FE_INEXACT): + Define to 0. + (GEN_ONE_TEST): Test inexact exceptions raised are as expected. + 2016-10-27 David S. Miller * sysdeps/unix/sysv/linux/sparc/sys/user.h: Include stddef.h diff --git a/stdlib/gen-tst-strtod-round.c b/stdlib/gen-tst-strtod-round.c index 1c2823f5bee..85279090ee6 100644 --- a/stdlib/gen-tst-strtod-round.c +++ b/stdlib/gen-tst-strtod-round.c @@ -50,12 +50,12 @@ string_to_fp (mpfr_t f, const char *s, mpfr_rnd_t rnd) mpfr_init2 (f2, 100000); int r0 = mpfr_strtofr (f2, s, NULL, 0, rnd); int r = mpfr_set (f, f2, rnd); - mpfr_subnormalize (f, r, rnd); + r |= mpfr_subnormalize (f, r, rnd); mpfr_clear (f2); return r0 | r; #else int r = mpfr_strtofr (f, s, NULL, 0, rnd); - mpfr_subnormalize (f, r, rnd); + r |= mpfr_subnormalize (f, r, rnd); return r; #endif } diff --git a/stdlib/strtod_l.c b/stdlib/strtod_l.c index 3d66eac7068..a6c226ee9f9 100644 --- a/stdlib/strtod_l.c +++ b/stdlib/strtod_l.c @@ -294,11 +294,14 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative, if (exponent > MAX_EXP) goto overflow; + bool half_bit = (round_limb & (((mp_limb_t) 1) << round_bit)) != 0; + bool more_bits_nonzero + = (more_bits + || (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0); if (round_away (negative, (retval[0] & 1) != 0, - (round_limb & (((mp_limb_t) 1) << round_bit)) != 0, - (more_bits - || (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0), + half_bit, + more_bits_nonzero, mode)) { mp_limb_t cy = __mpn_add_1 (retval, retval, RETURN_LIMB_SIZE, 1); @@ -325,6 +328,11 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative, overflow: return overflow_value (negative); + if (half_bit || more_bits_nonzero) + { + FLOAT force_inexact = (FLOAT) 1 + MIN_VALUE; + math_force_eval (force_inexact); + } return MPN2FLOAT (retval, exponent, negative); } diff --git a/stdlib/tst-strtod-round-data.h b/stdlib/tst-strtod-round-data.h index 1fd3aa87e1a..fc09bc91175 100644 --- a/stdlib/tst-strtod-round-data.h +++ b/stdlib/tst-strtod-round-data.h @@ -809,7 +809,7 @@ static const struct test tests[] = { TEST ("0.0000000000000000000000000000000000000000000021019476964872" "256063855943749348741969203929128147736576356024258346866240" "28790902229957282543182373046875", - true, + false, 0x8p-152, 0x1p-148, 0x8p-152, @@ -3454,7 +3454,7 @@ static const struct test tests[] = { 0xcp-152), TEST ("2.1019476964872256063855943749348741969203929128147736576356" "02425834686624028790902229957282543182373046875e-45", - true, + false, 0x8p-152, 0x1p-148, 0x8p-152, @@ -3550,7 +3550,7 @@ static const struct test tests[] = { -0xb.fffffffffffffffffffffffffff8p-152), TEST ("-2.101947696487225606385594374934874196920392912814773657635" "602425834686624028790902229957282543182373046875e-45", - true, + false, -0x1p-148, -0x1p-148, -0x8p-152, @@ -3646,7 +3646,7 @@ static const struct test tests[] = { 0x1.4p-148), TEST ("3.5032461608120426773093239582247903282006548546912894293926" "70709724477706714651503716595470905303955078125e-45", - true, + false, 0x1p-148, 0x1p-148, 0x1p-148, @@ -3742,7 +3742,7 @@ static const struct test tests[] = { -0x1.3fffffffffffffffffffffffffffp-148), TEST ("-3.503246160812042677309323958224790328200654854691289429392" "670709724477706714651503716595470905303955078125e-45", - true, + false, -0x1.8p-148, -0x1p-148, -0x1p-148, @@ -3865,7 +3865,7 @@ static const struct test tests[] = { 0x0p+0, 0x0p+0, 0x8p-152, - true, + false, 0x4p-1076, 0x8p-1076, 0x4p-1076, @@ -3880,7 +3880,7 @@ static const struct test tests[] = { 0x6p-1076, 0x6p-1076, 0x6p-1076, - true, + false, 0x4p-1076, 0x8p-1076, 0x4p-1076, @@ -3994,7 +3994,7 @@ static const struct test tests[] = { -0x0p+0, -0x0p+0, -0x0p+0, - true, + false, -0x8p-1076, -0x8p-1076, -0x4p-1076, @@ -4009,7 +4009,7 @@ static const struct test tests[] = { -0x6p-1076, -0x6p-1076, -0x6p-1076, - true, + false, -0x8p-1076, -0x8p-1076, -0x4p-1076, @@ -4486,7 +4486,7 @@ static const struct test tests[] = { 0x0p+0, 0x0p+0, 0x4p-1076, - true, + false, 0x8p-16448, 0x1p-16444, 0x8p-16448, @@ -5152,7 +5152,7 @@ static const struct test tests[] = { -0x0p+0, -0x0p+0, -0x0p+0, - true, + false, -0x1p-16444, -0x1p-16444, -0x8p-16448, @@ -5818,7 +5818,7 @@ static const struct test tests[] = { 0x0p+0, 0x0p+0, 0x4p-1076, - true, + false, 0x8p-16448, 0x1p-16444, 0x8p-16448, @@ -6484,7 +6484,7 @@ static const struct test tests[] = { -0x0p+0, -0x0p+0, -0x0p+0, - true, + false, -0x1p-16444, -0x1p-16444, -0x8p-16448, diff --git a/stdlib/tst-strtod-round-skeleton.c b/stdlib/tst-strtod-round-skeleton.c index 2e99dbdc215..89e09870ca9 100644 --- a/stdlib/tst-strtod-round-skeleton.c +++ b/stdlib/tst-strtod-round-skeleton.c @@ -157,8 +157,13 @@ struct test { #define STR(x) STRX (x) #define FNPFXS STR (FNPFX) +#ifndef FE_INEXACT +# define FE_INEXACT 0 +#endif + #define GEN_ONE_TEST(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \ { \ + feclearexcept (FE_INEXACT); \ FTYPE f = STRTO (FSUF) (s, NULL); \ if (f != expected->FSUF \ || (copysign ## CSUF) (1.0 ## LSUF, f) \ @@ -175,6 +180,19 @@ struct test { else \ printf ("ignoring this inexact result\n"); \ } \ + else if (FE_INEXACT != 0) \ + { \ + bool inexact_raised = fetestexcept (FE_INEXACT) != 0; \ + if (inexact_raised != !exact->FSUF) \ + { \ + printf (FNPFXS "to" #FSUF " (" STRM ") inexact %d " \ + "not %d\n", s, inexact_raised, !exact->FSUF); \ + if (EXCEPTION_TESTS (FTYPE)) \ + result = 1; \ + else \ + printf ("ignoring this exception error\n"); \ + } \ + } \ } static int