From 9743a399bf4d6da9a1dbdf7e8df07284c97df16f Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Sun, 9 Mar 2014 03:09:49 -0400 Subject: fix incorrect rounding in printf floating point corner cases the printf floating point formatting code contains an optimization to avoid computing digits that will be thrown away by rounding at the specified (or default) precision. while it was correctly retaining all places up to the last decimal place to be printed, it was not retaining enough precision to see the next nonzero decimal place in all cases. this could cause incorrect rounding down in round-to-even (default) rounding mode, for example, when printing 0.5+DBL_EPSILON with "%.0f". in the fix, LDBL_MANT_DIG/3 is a lazy (non-sharp) upper bound on the number of zeros between any two nonzero decimal digits. --- src/stdio/vfprintf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stdio/vfprintf.c b/src/stdio/vfprintf.c index 85701726..31c3d5dd 100644 --- a/src/stdio/vfprintf.c +++ b/src/stdio/vfprintf.c @@ -314,7 +314,7 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t) } while (e2<0) { uint32_t carry=0, *b; - int sh=MIN(9,-e2); + int sh=MIN(9,-e2), need=1+(p+LDBL_MANT_DIG/3+8)/9; for (d=a; d>sh) + carry; @@ -324,7 +324,7 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t) if (carry) *z++ = carry; /* Avoid (slow!) computation past requested precision */ b = (t|32)=='f' ? r : a; - if (z-b > 2+p/9) z = b+2+p/9; + if (z-b > need) z = b+need; e2+=sh; } -- cgit v1.2.1