This is the mail archive of the newlib@sourceware.org mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Bug in Cygwin strtod()


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;
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]