about summary refs log tree commit diff
path: root/stdlib/strtod_l.c
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2015-04-10 20:45:30 +0000
committerJoseph Myers <joseph@codesourcery.com>2015-04-10 20:45:30 +0000
commit5556d30caee170384553d2ae3247ec77a66b9ae8 (patch)
treef17624c702ee8f1304651ebe95145205f294273d /stdlib/strtod_l.c
parentb3c66c534f8a9dbee44aa4983814fc52008f0323 (diff)
downloadglibc-5556d30caee170384553d2ae3247ec77a66b9ae8.tar.gz
glibc-5556d30caee170384553d2ae3247ec77a66b9ae8.tar.xz
glibc-5556d30caee170384553d2ae3247ec77a66b9ae8.zip
Fix strtof decimal rounding close to half least subnormal (bug 18247).
Bug 18247 is an off-by-one error in strtof's determination of a
decimal exponent such that any value with that decimal exponent is at
most half the least subnormal and so the appropriate underflowing
value for the rounding mode can be determined with no
multiple-precision computations.  (Whether the value is in fact safe
despite the off-by-one depends on the floating-point format in
question.  It's wrong for float and for m68k ldbl-96 but not for other
supported formats.)  This patch corrects the computation of the
exponent in question to be safe in general, adding a comment
explaining the new computation.

Tested for x86_64.

	[BZ #18247]
	* stdlib/strtod_l.c (____STRTOF_INTERNAL): Decrease minimum
	decimal exponent by 1.
	* stdlib/tst-strtod-round-data: Add more tests.
	* stdlib/tst-strtod-round.c (tests): Regenerated.
Diffstat (limited to 'stdlib/strtod_l.c')
-rw-r--r--stdlib/strtod_l.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/stdlib/strtod_l.c b/stdlib/strtod_l.c
index c39bb35b09..e13ab1e7e1 100644
--- a/stdlib/strtod_l.c
+++ b/stdlib/strtod_l.c
@@ -1189,7 +1189,16 @@ ____STRTOF_INTERNAL (nptr, endptr, group, loc)
   if (__glibc_unlikely (exponent > MAX_10_EXP + 1 - (intmax_t) int_no))
     return overflow_value (negative);
 
-  if (__glibc_unlikely (exponent < MIN_10_EXP - (DIG + 1)))
+  /* 10^(MIN_10_EXP-1) is not normal.  Thus, 10^(MIN_10_EXP-1) /
+     2^MANT_DIG is below half the least subnormal, so anything with a
+     base-10 exponent less than the base-10 exponent (which is
+     MIN_10_EXP - 1 - ceil(MANT_DIG*log10(2))) of that value
+     underflows.  DIG is floor((MANT_DIG-1)log10(2)), so an exponent
+     below MIN_10_EXP - (DIG + 3) underflows.  But EXPONENT is
+     actually an exponent multiplied only by a fractional part, not an
+     integer part, so an exponent below MIN_10_EXP - (DIG + 2)
+     underflows.  */
+  if (__glibc_unlikely (exponent < MIN_10_EXP - (DIG + 2)))
     return underflow_value (negative);
 
   if (int_no > 0)
@@ -1356,7 +1365,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group, loc)
 
     assert (dig_no > int_no
 	    && exponent <= 0
-	    && exponent >= MIN_10_EXP - (DIG + 1));
+	    && exponent >= MIN_10_EXP - (DIG + 2));
 
     /* We need to compute MANT_DIG - BITS fractional bits that lie
        within the mantissa of the result, the following bit for