This is the mail archive of the
newlib@sourceware.org
mailing list for the newlib project.
Re: Bug in Cygwin strtod()
- From: Christian Bruel <christian dot bruel at st dot com>
- To: "newlib at sourceware dot org" <newlib at sourceware dot org>
- Date: Mon, 7 Jan 2013 11:27:05 +0100
- Subject: Re: Bug in Cygwin strtod()
- References: <1355878473.91036.YahooMailNeo@web121001.mail.ne1.yahoo.com> <50D118CE.8090108@gmail.com> <50D166D2.3030505@gmail.com> <20121219101618.GA13560@calimero.vinschen.de> <50D1A880.2080109@st.com> <20121219125804.GA4120@calimero.vinschen.de>
Hello,
Here is a less intrusive patch to fix the earlier issues on small
DBL_DIG targets. I added a testsuite file to track the values that
caused errors. Including original SH4 -m4-single-only failures and the
recent regression with the M_LN10 rounding.
The rounding code seems to assume that DBL_DIG is bigger than 9 when
reading the dval value. So I fixed the setting of dval so at the 9
digits are read (if less digits than 9 this is fine). This fixes the
problem, even if it's still possible that a fix in the rounding code
exists, but there are so many configuration settings that this looks
quite fragile to touch.
The problem seems to impact 32bit real targets, which are from the GCC
machine descriptions sh, rx, avr, rl78 and h8300.
Cheers
Christian
2012-12-07 Christian Bruel <christian.bruel@st.com>
* libc/stdlib/strtod.c (_strtod_r): Fix dval for small DBL_DIG.
* testsuite/newlib.stdlib/strtod1.c: Add regressions.
diff --exclude CVS -ruN src/newlib/libc/stdlib/strtod.c src.new/newlib/libc/stdlib/strtod.c
--- src/newlib/libc/stdlib/strtod.c 2012-12-19 11:16:00.000000000 +0100
+++ src.new/newlib/libc/stdlib/strtod.c 2013-01-07 10:53:01.000000000 +0100
@@ -326,18 +326,21 @@
}
for(; c >= '0' && c <= '9'; c = *++s) {
have_dig:
+
nz++;
if (c -= '0') {
nf += nz;
for(i = 1; i < nz; i++) {
- if (nd++ <= DBL_DIG + 1) {
+ if (nd++ <= (DBL_DIG + 1 >= 10
+ ? DBL_DIG + 1 : 10)) {
if (nd < 10)
y *= 10;
else
z *= 10;
}
}
- if (nd++ <= DBL_DIG + 1) {
+ if (nd++ <= (DBL_DIG + 1 >= 10 ?
+ DBL_DIG + 1 : 10)) {
if (nd < 10)
y = 10*y + c;
else
diff --exclude CVS -ruN src/newlib/testsuite/newlib.stdlib/strtod1.c src.new/newlib/testsuite/newlib.stdlib/strtod1.c
--- src/newlib/testsuite/newlib.stdlib/strtod1.c 1970-01-01 01:00:00.000000000 +0100
+++ src.new/newlib/testsuite/newlib.stdlib/strtod1.c 2013-01-07 10:53:41.000000000 +0100
@@ -0,0 +1,37 @@
+#include<math.h>
+#include<stdio.h>
+#include<stdlib.h>
+
+#define VAL1 1.00000001
+#define VAL2 10.0000000000000001
+#define VAL3 M_LN10
+
+#define xstr(s) str(s)
+#define str(s) #s
+
+void test(char *sval, double val)
+{
+ double value;
+
+ if ((value = strtod(sval, 0)) != val)
+ {
+#if __DBL_DIG__ == 15
+ printf("generate strtod - value: %0.15f %0.15f\n", value, val);
+#elif __DBL_DIG__ == 6
+ printf("generate strtod - value: %0.6f %0.6f\n", value, val);
+#else
+#error __DBL_DIG__
+#endif
+ abort();
+ }
+}
+
+int
+main()
+{
+ test(xstr(VAL1), VAL1);
+ test(xstr(VAL2), VAL2);
+ test(xstr(VAL3), VAL3);
+
+ return 0;
+}