printf("%.0f", 0.5) and round-to-even
Eric Blake
ebb9@byu.net
Thu Oct 2 12:33:00 GMT 2008
Eric Blake <ebb9 <at> byu.net> writes:
> > Based on a report on bug-gnu-utils:
> > http://lists.gnu.org/archive/html/bug-gnu-utils/2008-09/msg00055.html
> > It looks like the printf family could use a QoI improvement when dealing
with
> > IEEE round-to-even rules. I'll try and look at making this improvement in
> the
> > next few days.
OK to apply this patch? ldtoa.c was already attempting to handle round-to-even
semantics, but it goofed in two corner cases:
On printf("%.0f", 0.5), etoasc resulted in an intermediate string of " 5." and
ndigs==-1 (ie. the '5' has not yet been committed to), but since the last digit
was '5', it attempted to round to even and returned " 1E0" to _ldtoa_r. But
the correct approach is to treat it like 0.49, where the intermediate string
is " 4.", the function truncates and returns " 4E0", and _ldtoa_r uses ldp-
>outexpon to recognize that '4' was not committed to and cleans up the
truncation. In other words, only attempt round-to-even if ndigs is non-
negative, meaning that at least one digit in the output string has been
committed to, so that it makes sense to round.
The other bug is shared among printf("%.0f", 7.5), printf("%.1f", .75) and
printf("%.0e", .75). Here, etoasc results in an intermediate string of " 7.5&"
and ndigs==0 (ie. the '7' is committed, but the '5' is under suspicion).
Unfortunately, '.' is even, so the round-to-even check assumes that no
additional work is needed, and returns " 7E-1" to _ldtoa_r. The fix is to
skip '.' when checking if the previous digit ('7') needs rounding.
2008-09-30 Eric Blake <ebb9@byu.net>
* libc/stdlib/ldtoa.c (etoasc): Fix rounding to even when fraction
is 0.5 or 0.75.
Index: libc/stdlib/ldtoa.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdlib/ldtoa.c,v
retrieving revision 1.12
diff -u -p -r1.12 ldtoa.c
--- libc/stdlib/ldtoa.c 6 Jun 2007 19:24:28 -0000 1.12
+++ libc/stdlib/ldtoa.c 30 Sep 2008 18:34:48 -0000
@@ -3153,7 +3153,7 @@ if( digit > 4 )
emovo( y, t, ldp );
if( ecmp(t,ezero) != 0 )
goto roun; /* round to nearest */
- if( (*(s-1) & 1) == 0 )
+ if( ndigs < 0 || (*(s-1-(*(s-1)=='.')) & 1) == 0)
goto doexp; /* round to even */
}
/* Round up and propagate carry-outs */
More information about the Newlib
mailing list