libs/libc/stdio/lib_dtoa.c: Lots of risky turmoil to get this file closer to the NuttX coding style. Seems to check out, but still risky. libs/libc/stdio/lib_libdtoa.c: A fix for the %g format. The algorithm will sometimes generate number greater than the precision of type double. This adds a check if the precision has been exceeded and logic to remove the least significant garbage.

This commit is contained in:
Gregory Nutt
2019-02-16 18:08:38 -06:00
parent 79b3bec208
commit 67b16613ba
2 changed files with 729 additions and 538 deletions
+683 -526
View File
File diff suppressed because it is too large Load Diff
+46 -12
View File
@@ -58,26 +58,20 @@
* Pre-processor Definitions
****************************************************************************/
#define MAX_PREC 16
#ifndef MIN
# define MIN(a,b) (a < b ? a : b)
# define MIN(a,b) (a < b ? a : b)
#endif
#ifndef MAX
# define MAX(a,b) (a > b ? a : b)
# define MAX(a,b) (a > b ? a : b)
#endif
/* Use (almost) the maximim precision with %g 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.
/* Use the maximim precision with %g format if no precision is specified.
* NOTE: This may result in numbers with precision that exceeds the
* precision of type double.
*/
#define DOUBLE_PRECISON_MAX 13 /* vs 15 which is the maximum */
#define DOUBLE_PRECISON_MAX 15
/* Use a default precision of 6 for the %f format if no precision is
* specified.
@@ -107,6 +101,24 @@ static void zeroes(FAR struct lib_outstream_s *obj, int nzeroes)
}
}
/****************************************************************************
* Name: truncate_zeroes
*
* Description:
* Adjust the string length to eliminate zeros in the fractional part of
* the string.
*
****************************************************************************/
static inline int truncate_zeroes(FAR char *digits, int expt, int numlen)
{
for (; numlen > expt && digits[numlen - 1] == '0'; numlen--)
{
}
return numlen;
}
/****************************************************************************
* Name: lib_dtoa_string
*
@@ -216,6 +228,28 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec,
digits = __dtoa(value, 3, prec, &expt, &dsgn, &rve);
numlen = rve - digits;
/* If we are going to truncate trailing zeros, then make sure we have not
* exceeded the precision of type double.
*/
if (notrailing && numlen > DOUBLE_PRECISON_MAX)
{
/* Make sure there are fractional digits to truncate */
if (expt <= DOUBLE_PRECISON_MAX)
{
numlen = DOUBLE_PRECISON_MAX;
}
else
{
numlen = expt;
}
/* Shortening the string probably now exposes some trailing zeroes */
numlen = truncate_zeroes(digits, expt, numlen);
}
/* Avoid precision error from missing trailing zeroes */
numlen = MAX(expt, numlen);