From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 7868) id 55F113858D39; Fri, 26 Nov 2021 10:24:04 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 55F113858D39 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Takashi Yano To: newlib-cvs@sourceware.org Subject: [newlib-cygwin] ldtoa: Fix insufficient valid output digits for "%f" format. X-Act-Checkin: newlib-cygwin X-Git-Author: Takashi Yano X-Git-Refname: refs/heads/master X-Git-Oldrev: 4f47e64b11ed8d47c62fa89e9b971f44b7e9ab75 X-Git-Newrev: f885632f4f00c9a4a75d61f4b42c73554a0691b3 Message-Id: <20211126102404.55F113858D39@sourceware.org> Date: Fri, 26 Nov 2021 10:24:04 +0000 (GMT) X-BeenThere: newlib-cvs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Newlib GIT logs List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 26 Nov 2021 10:24:04 -0000 https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=f885632f4f00c9a4a75d61f4b42c73554a0691b3 commit f885632f4f00c9a4a75d61f4b42c73554a0691b3 Author: Takashi Yano Date: Fri Nov 26 06:47:27 2021 +0900 ldtoa: Fix insufficient valid output digits for "%f" format. - If the number has large integer part and small fraction part is specified in output format, e.g. printf("%.3f", sqrt(2)*1e60);, valid output digits were insufficient. This patch fixes the issue. Diff: --- newlib/libc/stdlib/ldtoa.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/newlib/libc/stdlib/ldtoa.c b/newlib/libc/stdlib/ldtoa.c index 1b32e801c..26c61948b 100644 --- a/newlib/libc/stdlib/ldtoa.c +++ b/newlib/libc/stdlib/ldtoa.c @@ -83,7 +83,7 @@ static void eclear (register short unsigned int *x); static void einfin (register short unsigned int *x, register LDPARMS * ldp); static void efloor (short unsigned int *x, short unsigned int *y, LDPARMS * ldp); -static void etoasc (short unsigned int *x, char *string, int ndigs, +static void etoasc (short unsigned int *x, char *string, int ndec, int ndigs, int outformat, LDPARMS * ldp); union uconv @@ -217,7 +217,7 @@ static const char *const ermsg[7] = { * e24toasc( &f, str, n ) single to ASCII string, n digits after decimal * e53toasc( &d, str, n ) double to ASCII string, n digits after decimal * e64toasc( &d, str, n ) long double to ASCII string - * etoasc(e,str,n,fmt,ldp)e to ASCII string, n digits after decimal + * etoasc(e,str,ndec,n,fmt,ldp)e to ASCII string, n digits after decimal * etoe24( e, &f ) convert e type to IEEE single precision * etoe53( e, &d ) convert e type to IEEE double precision * etoe64( e, &d ) convert e type to IEEE long double precision @@ -2839,23 +2839,33 @@ _ldtoa_r (struct _reent *ptr, long double d, int mode, int ndigits, /* This sanity limit must agree with the corresponding one in etoasc, to keep straight the returned value of outexpon. Note that we use a dynamic - limit now, either NDEC or NDEC_SML, depending on ndigits. See the usage - of "my_NDEC" in etoasc. */ - if (ndigits > NDEC) - ndigits = NDEC; + limit now, either ndec (<= NDEC) or NDEC_SML, depending on ndigits. */ + __int32_t ndec; + if (mode == 3) /* %f */ + { + __int32_t expon = (e[NE - 1] & 0x7fff) - (EXONE - 1); /* exponent part */ + /* log2(10) approximately 485/146 */ + ndec = expon * 146 / 485 + ndigits; + } + else /* %g/%e */ + ndec = ndigits; + if (ndec < 0) + ndec = 0; + if (ndec > NDEC) + ndec = NDEC; /* Allocate buffer if more than NDEC_SML digits are requested. */ - if (ndigits > NDEC_SML) + if (ndec > NDEC_SML) { - outbuf = (char *) _malloc_r (ptr, NDEC + MAX_EXP_DIGITS + 10); + outbuf = (char *) _malloc_r (ptr, ndec + MAX_EXP_DIGITS + 10); if (!outbuf) { - ndigits = NDEC_SML; + ndec = NDEC_SML; outbuf = outbuf_sml; } } - etoasc (e, outbuf, ndigits, mode, ldp); + etoasc (e, outbuf, (int) ndec, ndigits, mode, ldp); s = outbuf; if (eisinf (e) || eisnan (e)) { @@ -2992,8 +3002,8 @@ _ldcheck (long double *d) } /* _ldcheck */ static void -etoasc (short unsigned int *x, char *string, int ndigits, int outformat, - LDPARMS * ldp) +etoasc (short unsigned int *x, char *string, int ndec, int ndigits, + int outformat, LDPARMS * ldp) { long digit; unsigned short y[NI], t[NI], u[NI], w[NI]; @@ -3003,7 +3013,6 @@ etoasc (short unsigned int *x, char *string, int ndigits, int outformat, char *s, *ss; unsigned short m; unsigned short *equot = ldp->equot; - int my_NDEC = (ndigits > NDEC_SML) ? NDEC : NDEC_SML; ndigs = ndigits; rndsav = ldp->rndprc; @@ -3129,7 +3138,7 @@ tnzro: else { emovi (y, w); - for (i = 0; i < my_NDEC + 1; i++) + for (i = 0; i < ndec + 1; i++) { if ((w[NI - 1] & 0x7) != 0) break; @@ -3205,8 +3214,8 @@ isone: else if( ndigs < 0 ) ndigs = 0; */ - if (ndigs > my_NDEC) - ndigs = my_NDEC; + if (ndigs > ndec) + ndigs = ndec; if (digit == 10) { *s++ = '1';