summaryrefslogtreecommitdiffstats
path: root/nuttx
diff options
context:
space:
mode:
authorpatacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679>2012-08-06 02:14:36 +0000
committerpatacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679>2012-08-06 02:14:36 +0000
commit171dfd3f7f5094cb59f4f50fbf764f414f41c19a (patch)
tree01b886eb4714db11bada5d0ef28e7bd5f674dd92 /nuttx
parent55a1ed3e20d7582a829bd46bbc6408a65838d0ef (diff)
Fix a floating point presentation error
git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@5012 7fd9a85b-ad96-42d3-883c-3090e2eb8679
Diffstat (limited to 'nuttx')
-rw-r--r--nuttx/ChangeLog5
-rw-r--r--nuttx/TODO8
-rw-r--r--nuttx/lib/stdio/lib_libdtoa.c306
3 files changed, 102 insertions, 217 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index 6fd4979433..d57d9c4d87 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -3125,3 +3125,8 @@
* lib/stdio/lib_libvsprintf.c: Fieldwidth and justification were not
supported for the %s format. As a result, %s, %12s, and %-12s all
produced the same output.
+ * lib/stdio/lib_libdtoa.c: Fix several issues with presenting floating
+ point numbers (conversions are fine, but presentation was bad). This
+ is a critical bug fix if you use printf or sprintf to deal with floating
+ point numbers.
+
diff --git a/nuttx/TODO b/nuttx/TODO
index e2abce7f40..087977aee0 100644
--- a/nuttx/TODO
+++ b/nuttx/TODO
@@ -15,7 +15,7 @@ nuttx/
(5) Binary loaders (binfmt/)
(17) Network (net/, drivers/net)
(3) USB (drivers/usbdev, drivers/usbhost)
- (9) Libraries (lib/)
+ (10) Libraries (lib/)
(10) File system/Generic drivers (fs/, drivers/)
(5) Graphics subystem (graphics/)
(1) Pascal add-on (pcode/)
@@ -685,6 +685,12 @@ o Libraries (lib/)
Status: Open
Priority: Low -- more of a roadmap
+ Title: FLOATING POINT FORMATS
+ Description: Only the %f floating point format is supported. Others are accepted
+ but treated like %f.
+ Status: Open
+ Priority: Medium (this might important to someone.
+
o File system / Generic drivers (fs/, drivers/)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/nuttx/lib/stdio/lib_libdtoa.c b/nuttx/lib/stdio/lib_libdtoa.c
index b805d13a7e..2d4309abe5 100644
--- a/nuttx/lib/stdio/lib_libdtoa.c
+++ b/nuttx/lib/stdio/lib_libdtoa.c
@@ -48,7 +48,13 @@
* Pre-processor Definitions
****************************************************************************/
-#define MAXEXP 308
+#ifndef MIN
+# define MIN(a,b) (a < b ? a : b)
+#endif
+
+#ifndef MAX
+# define MAX(a,b) (a > b ? a : b)
+#endif
/****************************************************************************
* Private Type Declarations
@@ -58,10 +64,6 @@
* Private Function Prototypes
****************************************************************************/
-static char* cvt(double value, int ndigits, int flags, char *sign,
- int *decpt, int ch, int *length);
-static int exponent(char *p0, int exp, int fmtch);
-
/****************************************************************************
* Global Constant Data
****************************************************************************/
@@ -79,268 +81,122 @@ static int exponent(char *p0, int exp, int fmtch);
****************************************************************************/
/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: cvt
+ * Name: zeroes
+ *
+ * Description:
+ * Print the specified number of zeres
+ *
****************************************************************************/
-static char* cvt(double value, int ndigits, int flags, char *sign,
- int *decpt, int ch, int *length)
+static void zeroes(FAR struct lib_outstream_s *obj, int nzeroes)
{
- int mode, dsgn;
- char *digits, *bp, *rve;
-
- if (ch == 'f')
- {
- mode = 3; /* ndigits after the decimal point */
- }
- else
- {
- /* To obtain ndigits after the decimal point for the 'e' and 'E'
- * formats, round to ndigits + 1 significant figures.
- */
-
- if (ch == 'e' || ch == 'E')
- {
- ndigits++;
- }
- mode = 2; /* ndigits significant digits */
- }
-
- if (value < 0)
- {
- value = -value;
- *sign = '-';
- }
- else
- {
- *sign = '\000';
- }
+ int i;
- digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
- if ((ch != 'g' && ch != 'G') || IS_ALTFORM(flags))
+ for (i = nzeroes; i > 0; i--)
{
- /* Print trailing zeros */
-
- bp = digits + ndigits;
- if (ch == 'f')
- {
- if (*digits == '0' && value)
- {
- *decpt = -ndigits + 1;
- }
- bp += *decpt;
- }
-
- if (value == 0)
- {
- /* kludge for __dtoa irregularity */
-
- rve = bp;
- }
-
- while (rve < bp)
- {
- *rve++ = '0';
- }
+ obj->put(obj, '0');
}
-
- *length = rve - digits;
- return digits;
}
/****************************************************************************
- * Name: exponent
+ * Private Functions
****************************************************************************/
-static int exponent(FAR char *p0, int exp, int fmtch)
-{
- FAR char *p;
- FAR char *t;
- char expbuf[MAXEXP];
-
- p = p0;
- *p++ = fmtch;
- if (exp < 0)
- {
- exp = -exp;
- *p++ = '-';
- }
- else
- {
- *p++ = '+';
- }
-
- t = expbuf + MAXEXP;
- if (exp > 9)
- {
- do
- {
- *--t = (exp % 10) + '0';
- }
- while ((exp /= 10) > 9);
- *--t = exp + '0';
- for (; t < expbuf + MAXEXP; *p++ = *t++);
- }
- else
- {
- *p++ = '0';
- *p++ = exp + '0';
- }
- return (p - p0);
-}
-
/****************************************************************************
* Name: lib_dtoa
*
* Description:
* This is part of lib_vsprintf(). It handles the floating point formats.
+ * This version supports only the &f (with precision).
*
****************************************************************************/
-static void lib_dtoa(FAR struct lib_outstream_s *obj, int ch, int prec,
- uint8_t flags, double _double)
+static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec,
+ uint8_t flags, double value)
{
- FAR char *cp; /* Handy char pointer (short term usage) */
- FAR char *cp_free = NULL; /* BIONIC: copy of cp to be freed after usage */
- char expstr[7]; /* Buffer for exponent string */
- char sign; /* Temporary negative sign for floats */
- int expt; /* Integer value of exponent */
- int expsize = 0; /* Character count for expstr */
- int ndig; /* Actual number of digits returned by cvt */
- int size; /* Size of converted field or string */
+ FAR char *digits; /* String returned by __dtoa */
+ FAR char *digalloc; /* Copy of digits to be freed after usage */
+ FAR char *rve; /* Points to the end of the return value */
+ char sign; /* Temporary negative sign for floats */
+ int expt; /* Integer value of exponent */
+ int numlen; /* Actual number of digits returned by cvt */
+ int nchars; /* Number of characters to print */
+ int dsgn; /* Unused sign indicator */
int i;
- cp = cvt(_double, prec, flags, &sign, &expt, ch, &ndig);
- cp_free = cp;
+ /* Non-zero... positive or negative */
- if (ch == 'g' || ch == 'G')
+ if (value < 0)
{
- /* 'g' or 'G' fmt */
-
- if (expt <= -4 || expt > prec)
- {
- ch = (ch == 'g') ? 'e' : 'E';
- }
- else
- {
- ch = 'g';
- }
+ value = -value;
+ sign = '-';
}
-
- if (ch <= 'e')
+ else
{
- /* 'e' or 'E' fmt */
-
- --expt;
- expsize = exponent(expstr, expt, ch);
- size = expsize + ndig;
- if (ndig > 1 || IS_ALTFORM(flags))
- {
- ++size;
- }
+ sign = '\0';
}
- else if (ch == 'f')
- {
- /* f fmt */
- if (expt > 0)
- {
- size = expt;
- if (prec || IS_ALTFORM(flags))
- {
- size += prec + 1;
- }
- }
- else /* "0.X" */
- {
- size = prec + 2;
- }
- }
- else if (expt >= ndig)
- {
- /* fixed g fmt */
+ /* Perform the conversion */
- size = expt;
- if (IS_ALTFORM(flags))
- {
- ++size;
- }
- }
- else
- {
- size = ndig + (expt > 0 ? 1 : 2 - expt);
- }
+ digits = __dtoa(value, 3, prec, &expt, &dsgn, &rve);
+ digalloc = digits;
+ numlen = rve - digits;
if (sign)
{
obj->put(obj, '-');
}
- if (_double == 0)
+ /* Always print at least one digit to the right of the decimal point. */
+
+ prec = MAX(1, prec);
+
+ /* Special case exact zero or the case where the number is smaller than
+ * the print precision.
+ */
+
+ if (value == 0 || expt < -prec)
{
/* kludge for __dtoa irregularity */
obj->put(obj, '0');
- if (expt < ndig || IS_ALTFORM(flags))
- {
- obj->put(obj, '.');
-
- i = ndig - 1;
- while (i > 0)
- {
- obj->put(obj, '0');
- i--;
- }
- }
+ obj->put(obj, '.');
}
else if (expt <= 0)
{
obj->put(obj, '0');
obj->put(obj, '.');
- i = ndig;
- while (i > 0)
- {
- obj->put(obj, *cp);
- i--;
- cp++;
- }
- }
- else if (expt >= ndig)
- {
- i = ndig;
- while (i > 0)
- {
- obj->put(obj, *cp);
- i--;
- cp++;
- }
+ /* Print leading zeros */
- i = expt - ndig;
- while (i > 0)
+ if (expt < 0)
{
- obj->put(obj, '0');
- i--;
+ nchars = MIN(-expt, prec);
+ zeroes(obj, nchars);
+ prec -= nchars;
}
+
+ /* Print the significant digits */
- if (IS_ALTFORM(flags))
+ nchars = MIN(numlen, prec);
+ for (i = nchars; i > 0; i--)
{
- obj->put(obj, '.');
+ obj->put(obj, *digits);
+ digits++;
}
+
+ /* Decremnt to get the number of trailing zeroes to print */
+
+ prec -= nchars;
}
else
{
- /* Print the integer */
+ /* Print the integer part */
- i = expt;
- while (i > 0)
+ for (i = expt; i > 0; i--)
{
- obj->put(obj, *cp);
- i--;
- cp++;
+ obj->put(obj, *digits);
+ digits++;
}
/* Print the decimal place */
@@ -349,14 +205,32 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int ch, int prec,
/* Print the decimal */
- i = ndig - expt;
- while (i > 0)
+ numlen -= expt;
+ nchars = MIN(numlen, prec);
+
+ for (i = nchars; i > 0; i--)
{
- obj->put(obj, *cp);
- i--;
- cp++;
+ obj->put(obj, *digits);
+ digits++;
}
+
+ /* Decremnt to get the number of trailing zeroes to print */
+
+ prec -= nchars;
+ }
+
+ /* Finally, print any trailing zeroes */
+
+ zeroes(obj, prec);
+
+ /* Is this memory supposed to be freed or not? */
+
+#if 0
+ if (digalloc)
+ {
+ free(digalloc);
}
+#endif
}
/****************************************************************************