summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2011-04-05 09:16:40 -0400
committerRich Felker <dalias@aerifal.cx>2011-04-05 09:16:40 -0400
commitf9569662c08d371b85c77f025dd5c6e00b4a4c8b (patch)
tree9d57f468465a14481945927f3ed60bcd445644fe
parentbd1f6eba8ca41994e7b7aefbe1513bd1b24f1279 (diff)
downloadmusl-f9569662c08d371b85c77f025dd5c6e00b4a4c8b.tar.gz
fix various floating point rounding and formatting errors in *printf
-rw-r--r--src/stdio/vfprintf.c42
1 files changed, 25 insertions, 17 deletions
diff --git a/src/stdio/vfprintf.c b/src/stdio/vfprintf.c
index 8cbfd96e..2245d1da 100644
--- a/src/stdio/vfprintf.c
+++ b/src/stdio/vfprintf.c
@@ -193,7 +193,7 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
uint32_t *a, *d, *r, *z;
int e2=0, e, i, j, l;
char buf[9+LDBL_MANT_DIG/4], *s;
- const char *prefix="-+ ";
+ const char *prefix="-0X+0X 0X-0x+0x 0x";
int pl;
char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)], *estr;
@@ -201,10 +201,10 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
if (y<0 || 1/y<0) {
y=-y;
} else if (fl & MARK_POS) {
- prefix++;
+ prefix+=3;
} else if (fl & PAD_POS) {
- prefix+=2;
- } else pl=0;
+ prefix+=6;
+ } else prefix++, pl=0;
if (!isfinite(y)) {
char *s = (t&32)?"inf":"INF";
@@ -223,15 +223,23 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
long double round = 8.0;
int re;
+ if (t&32) prefix += 9;
+ pl += 2;
+
if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0;
else re=LDBL_MANT_DIG/4-1-p;
if (re) {
- if (pl && *prefix=='-') y=-y;
while (re--) round*=16;
- y+=round;
- y-=round;
- if (y<0) y=-y;
+ if (*prefix=='-') {
+ y=-y;
+ y-=round;
+ y+=round;
+ y=-y;
+ } else {
+ y+=round;
+ y-=round;
+ }
}
estr=fmt_u(e2<0 ? -e2 : e2, ebuf);
@@ -240,17 +248,17 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
*--estr = t+('p'-'a');
s=buf;
- *s++='0';
- *s++=t+('x'-'a');
do {
int x=y;
*s++=xdigits[x]|(t&32);
y=16*(y-x);
- if (s-buf==3 && (y||p>0||(fl&ALT_FORM))) *s++='.';
+ if (s-buf==1 && (y||p>0||(fl&ALT_FORM))) *s++='.';
} while (y);
- if (p<0) p = s-buf-4;
- l = 1 + p + (p || (fl&ALT_FORM)) + ebuf-estr;
+ if (p && s-buf-2 < p)
+ l = (p+2) + (ebuf-estr);
+ else
+ l = (s-buf) + (ebuf-estr);
pad(f, ' ', w, pl+l, fl);
out(f, prefix, pl);
@@ -258,12 +266,12 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
out(f, buf, s-buf);
pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0);
out(f, estr, ebuf-estr);
- pad(f, '0', w, pl+l, fl^LEFT_ADJ);
+ pad(f, ' ', w, pl+l, fl^LEFT_ADJ);
return MAX(w, pl+l);
}
if (p<0) p=6;
- y *= 0x1p28; e2-=28;
+ if (y) y *= 0x1p28, e2-=28;
if (e2<0) a=r=z=big;
else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1;
@@ -305,7 +313,7 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
else e=0;
/* Perform rounding: j is precision after the radix (possibly neg) */
- j = p - ((t|32)!='f')*e - ((t|32)=='g');
+ j = p - ((t|32)!='f')*e - ((t|32)=='g' && p);
if (j < 9*(z-r-1)) {
uint32_t x;
/* We avoid C's broken division of negative numbers */
@@ -347,7 +355,7 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
}
if (!(fl&ALT_FORM)) {
/* Count trailing zeros in last place */
- if (z>a) for (i=10, j=0; z[-1]%i==0; i*=10, j++);
+ if (z>a && z[-1]) for (i=10, j=0; z[-1]%i==0; i*=10, j++);
else j=9;
if ((t|32)=='f')
p = MIN(p,MAX(0,9*(z-r-1)-j));