]> sourceware.org Git - glibc.git/commitdiff
Fix strtod subnormal rounding (bug 30220)
authorJoseph Myers <josmyers@redhat.com>
Tue, 27 Aug 2024 12:41:02 +0000 (12:41 +0000)
committerArjun Shankar <arjun@redhat.com>
Fri, 27 Sep 2024 15:25:43 +0000 (17:25 +0200)
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.

(cherry picked from commit 457622c2fa8f9f7435822d5287a437bc8be8090d)

stdlib/strtod_l.c
stdlib/tst-strtod-round-data
stdlib/tst-strtod-round-data.h

index be515ce659b3553033d5c90c4532e0cd0f0fac75..beb97b3d0cf3191a765cb69930e9488bf75b034d 100644 (file)
@@ -222,6 +222,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)
@@ -292,6 +293,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.  */
index 84ab705709b24b6c5f9e64e3ba62ef9050a83ad3..9489fbcc9ce7eee26b30206d0e2df0e413d73c06 100644 (file)
 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
index 13e62dd2b0588a16e2f9cb96f4d758fd31639746..ed50eb2537bc175cc3d77d45c8c7b978c032e56f 100644 (file)
@@ -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),
 };
This page took 0.066844 seconds and 5 git commands to generate.