libs/libc/stdio: Fix the %f floating point output format.

This commit is contained in:
Gregory Nutt
2019-02-15 09:56:58 -06:00
parent 7b9d02d496
commit eb0223bc7f
3 changed files with 50 additions and 24 deletions
+2 -3
View File
@@ -121,9 +121,8 @@ config NANO_PRINTF
depends on !LIBC_LONG_LONG depends on !LIBC_LONG_LONG
---help--- ---help---
Replace printf code with version from newlib-nano. This version Replace printf code with version from newlib-nano. This version
provides improved floating point output support, including 'g' mode provides adds support for the 'g' format. However, it does not
as well as making the default 'f' format include digits past the include 'long long' support.
decimal point. However, it does not include 'long long' support.
config NANO_PRINTLEVEL config NANO_PRINTLEVEL
int "Nano printf support level" int "Nano printf support level"
+48 -10
View File
@@ -46,6 +46,7 @@
#include <nuttx/config.h> #include <nuttx/config.h>
#include <stdbool.h>
#include <math.h> #include <math.h>
#include <assert.h> #include <assert.h>
@@ -67,6 +68,17 @@
# define MAX(a,b) (a > b ? a : b) # define MAX(a,b) (a > b ? a : b)
#endif #endif
/* Use (almost) the maximim precision with %f format if no precision is
* specified. We do not use the full precision beause the least significant
* digits are probably garbage.
*
* REVISIT: This should be smarter. 15 digits is the maximum size of the
* number. The maximum precision is really 15 minus the number of digits
* in the integer part.
*/
#define DOUBLE_PRECISON_MAX 13 /* vs 15 which is the maximum */
/**************************************************************************** /****************************************************************************
* Private Functions * Private Functions
****************************************************************************/ ****************************************************************************/
@@ -132,6 +144,7 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec,
{ {
FAR char *digits; /* String returned by __dtoa */ FAR char *digits; /* String returned by __dtoa */
FAR char *rve; /* Points to the end of the return value */ FAR char *rve; /* Points to the end of the return value */
bool hasdot; /* True: precision specified */
int expt; /* Integer value of exponent */ int expt; /* Integer value of exponent */
int numlen; /* Actual number of digits returned by cvt */ int numlen; /* Actual number of digits returned by cvt */
int nchars; /* Number of characters to print */ int nchars; /* Number of characters to print */
@@ -149,6 +162,14 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec,
DEBUGASSERT(up_interrupt_context() == false); DEBUGASSERT(up_interrupt_context() == false);
#endif #endif
/* Set to default precision if none specified */
hasdot = IS_HASDOT(flags);
if (!hasdot && prec == 0)
{
prec = DOUBLE_PRECISON_MAX;
}
/* Special handling for NaN and Infinity */ /* Special handling for NaN and Infinity */
if (isnan(value)) if (isnan(value))
@@ -178,8 +199,8 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec,
/* Perform the conversion */ /* Perform the conversion */
digits = __dtoa(value, 3, prec, &expt, &dsgn, &rve); digits = __dtoa(value, 3, prec, &expt, &dsgn, &rve);
numlen = rve - digits; numlen = rve - digits;
/* Avoid precision error from missing trailing zeroes */ /* Avoid precision error from missing trailing zeroes */
@@ -198,7 +219,7 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec,
* the print precision. * the print precision.
*/ */
if (value == 0 || expt < -prec) if (value == 0 || (expt < (hasdot ? -prec : 0)))
{ {
/* kludge for __dtoa irregularity */ /* kludge for __dtoa irregularity */
@@ -208,13 +229,20 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec,
* particular precision is requested. * particular precision is requested.
*/ */
if (prec > 0 || IS_ALTFORM(flags)) if ((prec > 0 && hasdot) || IS_ALTFORM(flags))
{ {
obj->put(obj, '.'); obj->put(obj, '.');
/* Always print at least one digit to the right of the decimal point. */ /* Always print at least one digit to the right of the decimal point. */
prec = MAX(1, prec); if (hasdot)
{
prec = MAX(1, prec);
}
else
{
prec = MAX(1, numlen);
}
} }
} }
@@ -222,7 +250,6 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec,
else else
{ {
/* Handle the case where the value is less than 1.0 (in magnitude) and /* Handle the case where the value is less than 1.0 (in magnitude) and
* will need a leading zero. * will need a leading zero.
*/ */
@@ -239,7 +266,7 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec,
/* Print any leading zeros to the right of the decimal point */ /* Print any leading zeros to the right of the decimal point */
if (expt < 0) if (expt < 0 || hasdot)
{ {
nchars = MIN(-expt, prec); nchars = MIN(-expt, prec);
zeroes(obj, nchars); zeroes(obj, nchars);
@@ -277,7 +304,8 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec,
* requested. * requested.
*/ */
if (numlen > 0 || prec > 0 || IS_ALTFORM(flags)) if (numlen > 0 || (prec > 0 && hasdot) ||
IS_ALTFORM(flags))
{ {
/* Print the decimal point */ /* Print the decimal point */
@@ -287,7 +315,14 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec,
* point. * point.
*/ */
prec = MAX(1, prec); if (hasdot)
{
prec = MAX(1, prec);
}
else
{
prec = MAX(1, numlen);
}
} }
} }
@@ -319,7 +354,10 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec,
/* Finally, print any trailing zeroes */ /* Finally, print any trailing zeroes */
zeroes(obj, prec); if (hasdot)
{
zeroes(obj, prec);
}
} }
/**************************************************************************** /****************************************************************************
-11
View File
@@ -118,10 +118,6 @@
# define FMT_PREV src-- /* Backup to the previous character */ # define FMT_PREV src-- /* Backup to the previous character */
#endif #endif
/* Default precision to use with %f format if no precision is specified. */
#define FLOAT_PRECISION_DEFAULT 6
/**************************************************************************** /****************************************************************************
* Private Type Declarations * Private Type Declarations
****************************************************************************/ ****************************************************************************/
@@ -1559,13 +1555,6 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, FAR const IPTR char *src,
double dblval = va_arg(ap, double); double dblval = va_arg(ap, double);
int dblsize; int dblsize;
/* Set to default precision if none specified */
if (!IS_HASDOT(flags) && trunc == 0)
{
trunc = FLOAT_PRECISION_DEFAULT;
}
/* Get the width of the output */ /* Get the width of the output */
dblsize = getdblsize(FMT_CHAR, trunc, flags, dblval); dblsize = getdblsize(FMT_CHAR, trunc, flags, dblval);