diff --git a/libs/libc/stdio/Kconfig b/libs/libc/stdio/Kconfig index fc30f34bfa..11d93e3893 100644 --- a/libs/libc/stdio/Kconfig +++ b/libs/libc/stdio/Kconfig @@ -121,9 +121,8 @@ config NANO_PRINTF depends on !LIBC_LONG_LONG ---help--- Replace printf code with version from newlib-nano. This version - provides improved floating point output support, including 'g' mode - as well as making the default 'f' format include digits past the - decimal point. However, it does not include 'long long' support. + provides adds support for the 'g' format. However, it does not + include 'long long' support. config NANO_PRINTLEVEL int "Nano printf support level" diff --git a/libs/libc/stdio/lib_libdtoa.c b/libs/libc/stdio/lib_libdtoa.c index 861930b3f0..1796393a65 100644 --- a/libs/libc/stdio/lib_libdtoa.c +++ b/libs/libc/stdio/lib_libdtoa.c @@ -46,6 +46,7 @@ #include +#include #include #include @@ -67,6 +68,17 @@ # define MAX(a,b) (a > b ? a : b) #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 ****************************************************************************/ @@ -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 *rve; /* Points to the end of the return value */ + bool hasdot; /* True: precision specified */ int expt; /* Integer value of exponent */ int numlen; /* Actual number of digits returned by cvt */ 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); #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 */ if (isnan(value)) @@ -178,8 +199,8 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec, /* Perform the conversion */ - digits = __dtoa(value, 3, prec, &expt, &dsgn, &rve); - numlen = rve - digits; + digits = __dtoa(value, 3, prec, &expt, &dsgn, &rve); + numlen = rve - digits; /* 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. */ - if (value == 0 || expt < -prec) + if (value == 0 || (expt < (hasdot ? -prec : 0))) { /* 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. */ - if (prec > 0 || IS_ALTFORM(flags)) + if ((prec > 0 && hasdot) || IS_ALTFORM(flags)) { obj->put(obj, '.'); /* 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 { - /* Handle the case where the value is less than 1.0 (in magnitude) and * 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 */ - if (expt < 0) + if (expt < 0 || hasdot) { nchars = MIN(-expt, prec); zeroes(obj, nchars); @@ -277,7 +304,8 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec, * requested. */ - if (numlen > 0 || prec > 0 || IS_ALTFORM(flags)) + if (numlen > 0 || (prec > 0 && hasdot) || + IS_ALTFORM(flags)) { /* Print the decimal point */ @@ -287,7 +315,14 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec, * 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 */ - zeroes(obj, prec); + if (hasdot) + { + zeroes(obj, prec); + } } /**************************************************************************** diff --git a/libs/libc/stdio/lib_libvsprintf.c b/libs/libc/stdio/lib_libvsprintf.c index 2d8758a26e..d84b785486 100644 --- a/libs/libc/stdio/lib_libvsprintf.c +++ b/libs/libc/stdio/lib_libvsprintf.c @@ -118,10 +118,6 @@ # define FMT_PREV src-- /* Backup to the previous character */ #endif -/* Default precision to use with %f format if no precision is specified. */ - -#define FLOAT_PRECISION_DEFAULT 6 - /**************************************************************************** * 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); 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 */ dblsize = getdblsize(FMT_CHAR, trunc, flags, dblval);