commit 457622c2fa8f9f7435822d5287a437bc8be8090d Author: Joseph Myers Date: Tue Aug 27 12:41:02 2024 +0000 Fix strtod subnormal rounding (bug 30220) As reported in bug 30220, the implementation of strtod-family functions has a bug in the following case: the input string would, with infinite exponent range, take one more bit to represent than is available in the normal precision of the return type; the value represented is in the subnormal range; and there are no nonzero bits in the value, below those that can be represented in subnormal precision, other than the least significant bit and possibly the 0.5ulp bit. In this case, round_and_return ends up discarding the least significant bit. Fix by saving that bit to merge into more_bits (it can't be merged in at the time it's computed, because more_bits mustn't include this bit in the case of after-rounding tininess detection checking if the result is still subnormal when rounded to normal precision, so merging this bit into more_bits needs to take place after that check). Tested for x86_64. diff --git a/stdlib/strtod_l.c b/stdlib/strtod_l.c index 5a54d99ae8663641..49b88e9a86be8441 100644 --- a/stdlib/strtod_l.c +++ b/stdlib/strtod_l.c @@ -223,6 +223,7 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative, mp_size_t shift = MIN_EXP - 1 - exponent; bool is_tiny = true; + bool old_half_bit = (round_limb & (((mp_limb_t) 1) << round_bit)) != 0; more_bits |= (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0; if (shift == MANT_DIG) @@ -293,6 +294,7 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative, round_bit = shift - 1; (void) __mpn_rshift (retval, retval, RETURN_LIMB_SIZE, shift); } + more_bits |= old_half_bit; /* This is a hook for the m68k long double format, where the exponent bias is the same for normalized and denormalized numbers. */ diff --git a/stdlib/tst-strtod-round-data b/stdlib/tst-strtod-round-data index 84ab705709b24b6c..9489fbcc9ce7eee2 100644 --- a/stdlib/tst-strtod-round-data +++ b/stdlib/tst-strtod-round-data @@ -265,3 +265,15 @@ 1.000000000000000000000000000000000385185988877447170611195588516985463707620329643077639047987759113311767578125 1.0000000000000000000000000000000001925929944387235853055977942584927318538101648215388195239938795566558837890625 1.00000000000000000000000000000000009629649721936179265279889712924636592690508241076940976199693977832794189453125 +0x30000002222225p-1077 +0x0.7fffffffffffeap-1022 +0x0.7fffffffffffe9p-1022 +0x0.7ffffd4p-126 +0x0.7ffffffffffffffd4p-16382 +0x0.7ffffffffffffffd4p-16383 +0x0.7ffffffffffffffffffffffffffeap-16382 +0x0.7000004p-126 +0x0.70000000000002p-1022 +0x0.70000000000000004p-16382 +0x0.70000000000000004p-16383 +0x0.70000000000000000000000000002p-16382 diff --git a/stdlib/tst-strtod-round-data.h b/stdlib/tst-strtod-round-data.h index 13e62dd2b0588a16..ed50eb2537bc175c 100644 --- a/stdlib/tst-strtod-round-data.h +++ b/stdlib/tst-strtod-round-data.h @@ -15437,4 +15437,376 @@ static const struct test tests[] = { 0x1p+0, false, false, 0x1p+0, false, false, 0x1.0000000000000000000000000001p+0, false, false), + TEST ("0x30000002222225p-1077", + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x8p-152, false, true, + false, + 0x1.800000111111p-1024, false, true, + 0x1.8000001111114p-1024, false, true, + 0x1.800000111111p-1024, false, true, + 0x1.8000001111114p-1024, false, true, + true, + 0x1.80000011111128p-1024, false, false, + 0x1.80000011111128p-1024, false, false, + 0x1.80000011111128p-1024, false, false, + 0x1.80000011111128p-1024, false, false, + true, + 0x1.80000011111128p-1024, false, false, + 0x1.80000011111128p-1024, false, false, + 0x1.80000011111128p-1024, false, false, + 0x1.80000011111128p-1024, false, false, + false, + 0x1.800000111111p-1024, false, true, + 0x1.8000001111114p-1024, false, true, + 0x1.800000111111p-1024, false, true, + 0x1.8000001111114p-1024, false, true, + true, + 0x1.80000011111128p-1024, false, false, + 0x1.80000011111128p-1024, false, false, + 0x1.80000011111128p-1024, false, false, + 0x1.80000011111128p-1024, false, false), + TEST ("0x0.7fffffffffffeap-1022", + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x8p-152, false, true, + false, + 0x1.ffffffffffff8p-1024, false, true, + 0x1.ffffffffffffcp-1024, false, true, + 0x1.ffffffffffff8p-1024, false, true, + 0x1.ffffffffffffcp-1024, false, true, + true, + 0x1.ffffffffffffa8p-1024, false, false, + 0x1.ffffffffffffa8p-1024, false, false, + 0x1.ffffffffffffa8p-1024, false, false, + 0x1.ffffffffffffa8p-1024, false, false, + true, + 0x1.ffffffffffffa8p-1024, false, false, + 0x1.ffffffffffffa8p-1024, false, false, + 0x1.ffffffffffffa8p-1024, false, false, + 0x1.ffffffffffffa8p-1024, false, false, + false, + 0x1.ffffffffffff8p-1024, false, true, + 0x1.ffffffffffffcp-1024, false, true, + 0x1.ffffffffffff8p-1024, false, true, + 0x1.ffffffffffffcp-1024, false, true, + true, + 0x1.ffffffffffffa8p-1024, false, false, + 0x1.ffffffffffffa8p-1024, false, false, + 0x1.ffffffffffffa8p-1024, false, false, + 0x1.ffffffffffffa8p-1024, false, false), + TEST ("0x0.7fffffffffffe9p-1022", + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x8p-152, false, true, + false, + 0x1.ffffffffffff8p-1024, false, true, + 0x1.ffffffffffffcp-1024, false, true, + 0x1.ffffffffffff8p-1024, false, true, + 0x1.ffffffffffffcp-1024, false, true, + true, + 0x1.ffffffffffffa4p-1024, false, false, + 0x1.ffffffffffffa4p-1024, false, false, + 0x1.ffffffffffffa4p-1024, false, false, + 0x1.ffffffffffffa4p-1024, false, false, + true, + 0x1.ffffffffffffa4p-1024, false, false, + 0x1.ffffffffffffa4p-1024, false, false, + 0x1.ffffffffffffa4p-1024, false, false, + 0x1.ffffffffffffa4p-1024, false, false, + false, + 0x1.ffffffffffff8p-1024, false, true, + 0x1.ffffffffffffcp-1024, false, true, + 0x1.ffffffffffff8p-1024, false, true, + 0x1.ffffffffffffcp-1024, false, true, + true, + 0x1.ffffffffffffa4p-1024, false, false, + 0x1.ffffffffffffa4p-1024, false, false, + 0x1.ffffffffffffa4p-1024, false, false, + 0x1.ffffffffffffa4p-1024, false, false), + TEST ("0x0.7ffffd4p-126", + false, + 0x1.fffffp-128, false, true, + 0x1.fffff8p-128, false, true, + 0x1.fffffp-128, false, true, + 0x1.fffff8p-128, false, true, + true, + 0x1.fffff5p-128, false, false, + 0x1.fffff5p-128, false, false, + 0x1.fffff5p-128, false, false, + 0x1.fffff5p-128, false, false, + true, + 0x1.fffff5p-128, false, false, + 0x1.fffff5p-128, false, false, + 0x1.fffff5p-128, false, false, + 0x1.fffff5p-128, false, false, + true, + 0x1.fffff5p-128, false, false, + 0x1.fffff5p-128, false, false, + 0x1.fffff5p-128, false, false, + 0x1.fffff5p-128, false, false, + true, + 0x1.fffff5p-128, false, false, + 0x1.fffff5p-128, false, false, + 0x1.fffff5p-128, false, false, + 0x1.fffff5p-128, false, false, + true, + 0x1.fffff5p-128, false, false, + 0x1.fffff5p-128, false, false, + 0x1.fffff5p-128, false, false, + 0x1.fffff5p-128, false, false), + TEST ("0x0.7ffffffffffffffd4p-16382", + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x8p-152, false, true, + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x4p-1076, false, true, + false, + 0x1.fffffffffffffffp-16384, false, true, + 0x1.fffffffffffffff8p-16384, false, true, + 0x1.fffffffffffffffp-16384, false, true, + 0x1.fffffffffffffff8p-16384, false, true, + false, + 0x1.fffffffffffffff4p-16384, false, true, + 0x1.fffffffffffffff4p-16384, false, true, + 0x1.fffffffffffffff4p-16384, false, true, + 0x1.fffffffffffffff8p-16384, false, true, + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x4p-1076, false, true, + true, + 0x1.fffffffffffffff5p-16384, false, false, + 0x1.fffffffffffffff5p-16384, false, false, + 0x1.fffffffffffffff5p-16384, false, false, + 0x1.fffffffffffffff5p-16384, false, false), + TEST ("0x0.7ffffffffffffffd4p-16383", + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x8p-152, false, true, + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x4p-1076, false, true, + false, + 0xf.ffffffffffffff8p-16388, false, true, + 0xf.ffffffffffffff8p-16388, false, true, + 0xf.ffffffffffffff8p-16388, false, true, + 0x1p-16384, false, true, + false, + 0xf.ffffffffffffff8p-16388, false, true, + 0xf.ffffffffffffffcp-16388, false, true, + 0xf.ffffffffffffff8p-16388, false, true, + 0xf.ffffffffffffffcp-16388, false, true, + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x4p-1076, false, true, + true, + 0xf.ffffffffffffffa8p-16388, false, false, + 0xf.ffffffffffffffa8p-16388, false, false, + 0xf.ffffffffffffffa8p-16388, false, false, + 0xf.ffffffffffffffa8p-16388, false, false), + TEST ("0x0.7ffffffffffffffffffffffffffeap-16382", + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x8p-152, false, true, + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x4p-1076, false, true, + false, + 0x1.fffffffffffffff8p-16384, false, true, + 0x2p-16384, false, true, + 0x1.fffffffffffffff8p-16384, false, true, + 0x2p-16384, false, true, + false, + 0x1.fffffffffffffffcp-16384, false, true, + 0x2p-16384, false, true, + 0x1.fffffffffffffffcp-16384, false, true, + 0x2p-16384, false, true, + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x4p-1076, false, true, + false, + 0x1.fffffffffffffffffffffffffff8p-16384, false, true, + 0x1.fffffffffffffffffffffffffffcp-16384, false, true, + 0x1.fffffffffffffffffffffffffff8p-16384, false, true, + 0x1.fffffffffffffffffffffffffffcp-16384, false, true), + TEST ("0x0.7000004p-126", + false, + 0x1.cp-128, false, true, + 0x1.cp-128, false, true, + 0x1.cp-128, false, true, + 0x1.c00008p-128, false, true, + true, + 0x1.c00001p-128, false, false, + 0x1.c00001p-128, false, false, + 0x1.c00001p-128, false, false, + 0x1.c00001p-128, false, false, + true, + 0x1.c00001p-128, false, false, + 0x1.c00001p-128, false, false, + 0x1.c00001p-128, false, false, + 0x1.c00001p-128, false, false, + true, + 0x1.c00001p-128, false, false, + 0x1.c00001p-128, false, false, + 0x1.c00001p-128, false, false, + 0x1.c00001p-128, false, false, + true, + 0x1.c00001p-128, false, false, + 0x1.c00001p-128, false, false, + 0x1.c00001p-128, false, false, + 0x1.c00001p-128, false, false, + true, + 0x1.c00001p-128, false, false, + 0x1.c00001p-128, false, false, + 0x1.c00001p-128, false, false, + 0x1.c00001p-128, false, false), + TEST ("0x0.70000000000002p-1022", + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x8p-152, false, true, + false, + 0x1.cp-1024, false, true, + 0x1.cp-1024, false, true, + 0x1.cp-1024, false, true, + 0x1.c000000000004p-1024, false, true, + true, + 0x1.c0000000000008p-1024, false, false, + 0x1.c0000000000008p-1024, false, false, + 0x1.c0000000000008p-1024, false, false, + 0x1.c0000000000008p-1024, false, false, + true, + 0x1.c0000000000008p-1024, false, false, + 0x1.c0000000000008p-1024, false, false, + 0x1.c0000000000008p-1024, false, false, + 0x1.c0000000000008p-1024, false, false, + false, + 0x1.cp-1024, false, true, + 0x1.cp-1024, false, true, + 0x1.cp-1024, false, true, + 0x1.c000000000004p-1024, false, true, + true, + 0x1.c0000000000008p-1024, false, false, + 0x1.c0000000000008p-1024, false, false, + 0x1.c0000000000008p-1024, false, false, + 0x1.c0000000000008p-1024, false, false), + TEST ("0x0.70000000000000004p-16382", + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x8p-152, false, true, + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x4p-1076, false, true, + false, + 0x1.cp-16384, false, true, + 0x1.cp-16384, false, true, + 0x1.cp-16384, false, true, + 0x1.c000000000000008p-16384, false, true, + false, + 0x1.cp-16384, false, true, + 0x1.cp-16384, false, true, + 0x1.cp-16384, false, true, + 0x1.c000000000000004p-16384, false, true, + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x4p-1076, false, true, + true, + 0x1.c000000000000001p-16384, false, false, + 0x1.c000000000000001p-16384, false, false, + 0x1.c000000000000001p-16384, false, false, + 0x1.c000000000000001p-16384, false, false), + TEST ("0x0.70000000000000004p-16383", + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x8p-152, false, true, + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x4p-1076, false, true, + false, + 0xep-16388, false, true, + 0xep-16388, false, true, + 0xep-16388, false, true, + 0xe.000000000000008p-16388, false, true, + false, + 0xep-16388, false, true, + 0xep-16388, false, true, + 0xep-16388, false, true, + 0xe.000000000000004p-16388, false, true, + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x4p-1076, false, true, + true, + 0xe.0000000000000008p-16388, false, false, + 0xe.0000000000000008p-16388, false, false, + 0xe.0000000000000008p-16388, false, false, + 0xe.0000000000000008p-16388, false, false), + TEST ("0x0.70000000000000000000000000002p-16382", + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x8p-152, false, true, + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x4p-1076, false, true, + false, + 0x1.cp-16384, false, true, + 0x1.cp-16384, false, true, + 0x1.cp-16384, false, true, + 0x1.c000000000000008p-16384, false, true, + false, + 0x1.cp-16384, false, true, + 0x1.cp-16384, false, true, + 0x1.cp-16384, false, true, + 0x1.c000000000000004p-16384, false, true, + false, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x0p+0, false, true, + 0x4p-1076, false, true, + false, + 0x1.cp-16384, false, true, + 0x1.cp-16384, false, true, + 0x1.cp-16384, false, true, + 0x1.c000000000000000000000000004p-16384, false, true), };