This is the mail archive of the mailing list for the newlib project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: printf("%.0f", 0.5) and round-to-even

Eric Blake <ebb9 <at>> writes:

> > Based on a report on bug-gnu-utils:
> >
> > It looks like the printf family could use a QoI improvement when dealing 
> > 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  <>

	* 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 */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]