[Python-checkins] r59725 - in python/trunk: Lib/test/test_builtin.py Lib/test/test_float.py Python/pystrtod.c

guido.van.rossum python-checkins at python.org
Sat Jan 5 01:59:59 CET 2008


Author: guido.van.rossum
Date: Sat Jan  5 01:59:59 2008
New Revision: 59725

Modified:
   python/trunk/Lib/test/test_builtin.py
   python/trunk/Lib/test/test_float.py
   python/trunk/Python/pystrtod.c
Log:
Patch #1725 by Mark Dickinson, fixes incorrect conversion of -1e1000
and adds errors for -0x.


Modified: python/trunk/Lib/test/test_builtin.py
==============================================================================
--- python/trunk/Lib/test/test_builtin.py	(original)
+++ python/trunk/Lib/test/test_builtin.py	Sat Jan  5 01:59:59 2008
@@ -619,6 +619,11 @@
         self.assertEqual(float("  3.14  "), 3.14)
         self.assertRaises(ValueError, float, "  0x3.1  ")
         self.assertRaises(ValueError, float, "  -0x3.p-1  ")
+        self.assertRaises(ValueError, float, "  +0x3.p-1  ")
+        self.assertRaises(ValueError, float, "++3.14")
+        self.assertRaises(ValueError, float, "+-3.14")
+        self.assertRaises(ValueError, float, "-+3.14")
+        self.assertRaises(ValueError, float, "--3.14")
         if have_unicode:
             self.assertEqual(float(unicode("  3.14  ")), 3.14)
             self.assertEqual(float(unicode("  \u0663.\u0661\u0664  ",'raw-unicode-escape')), 3.14)
@@ -648,6 +653,7 @@
         self.assertRaises(ValueError, float, "  -3,14  ")
         self.assertRaises(ValueError, float, "  0x3.1  ")
         self.assertRaises(ValueError, float, "  -0x3.p-1  ")
+        self.assertRaises(ValueError, float, "  +0x3.p-1  ")
         self.assertEqual(float("  25.e-1  "), 2.5)
         self.assertEqual(fcmp(float("  .25e-1  "), .025), 0)
 

Modified: python/trunk/Lib/test/test_float.py
==============================================================================
--- python/trunk/Lib/test/test_float.py	(original)
+++ python/trunk/Lib/test/test_float.py	Sat Jan  5 01:59:59 2008
@@ -121,6 +121,13 @@
             self.assertEquals(pos_pos(), neg_pos())
             self.assertEquals(pos_neg(), neg_neg())
 
+    if float.__getformat__("double").startswith("IEEE"):
+        def test_underflow_sign(self):
+            import math
+            # check that -1e-1000 gives -0.0, not 0.0
+            self.assertEquals(math.atan2(-1e-1000, -1), math.atan2(-0.0, -1))
+            self.assertEquals(math.atan2(float('-1e-1000'), -1),
+                              math.atan2(-0.0, -1))
 
 class ReprTestCase(unittest.TestCase):
     def test_repr(self):

Modified: python/trunk/Python/pystrtod.c
==============================================================================
--- python/trunk/Python/pystrtod.c	(original)
+++ python/trunk/Python/pystrtod.c	Sat Jan  5 01:59:59 2008
@@ -48,6 +48,8 @@
 	size_t decimal_point_len;
 	const char *p, *decimal_point_pos;
 	const char *end = NULL; /* Silence gcc */
+	const char *digits_pos = NULL;
+	int negate = 0;
 
 	assert(nptr != NULL);
 
@@ -60,18 +62,41 @@
 	assert(decimal_point_len != 0);
 
 	decimal_point_pos = NULL;
+
+	/* We process any leading whitespace and the optional sign manually,
+	   then pass the remainder to the system strtod.  This ensures that
+	   the result of an underflow has the correct sign. (bug #1725)  */
+
+	p = nptr;
+	/* Skip leading space */
+	while (ISSPACE(*p))
+		p++;
+
+	/* Process leading sign, if present */
+	if (*p == '-') {
+		negate = 1;
+		p++;
+	} else if (*p == '+') {
+		p++;
+	}
+
+	/* What's left should begin with a digit, a decimal point, or one of
+	   the letters i, I, n, N. It should not begin with 0x or 0X */
+	if ((!ISDIGIT(*p) &&
+	     *p != '.' && *p != 'i' && *p != 'I' && *p != 'n' && *p != 'N')
+	    ||
+	    (*p == '0' && (p[1] == 'x' || p[1] == 'X')))
+	{
+		if (endptr)
+			*endptr = (char*)nptr;
+		errno = EINVAL;
+		return val;
+	}
+	digits_pos = p;
+
 	if (decimal_point[0] != '.' || 
 	    decimal_point[1] != 0)
 	{
-		p = nptr;
-		  /* Skip leading space */
-		while (ISSPACE(*p))
-			p++;
-
-		  /* Skip leading optional sign */
-		if (*p == '+' || *p == '-')
-			p++;
-
 		while (ISDIGIT(*p))
 			p++;
 
@@ -93,7 +118,8 @@
 		else if (strncmp(p, decimal_point, decimal_point_len) == 0)
 		{
 			/* Python bug #1417699 */
-			*endptr = (char*)nptr;
+			if (endptr)
+				*endptr = (char*)nptr;
 			errno = EINVAL;
 			return val;
 		}
@@ -109,7 +135,8 @@
 		char *copy, *c;
 
 		/* We need to convert the '.' to the locale specific decimal point */
-		copy = (char *)PyMem_MALLOC(end - nptr + 1 + decimal_point_len);
+		copy = (char *)PyMem_MALLOC(end - digits_pos +
+					    1 + decimal_point_len);
 		if (copy == NULL) {
 			if (endptr)
 				*endptr = (char *)nptr;
@@ -118,8 +145,8 @@
 		}
 
 		c = copy;
-		memcpy(c, nptr, decimal_point_pos - nptr);
-		c += decimal_point_pos - nptr;
+		memcpy(c, digits_pos, decimal_point_pos - digits_pos);
+		c += decimal_point_pos - digits_pos;
 		memcpy(c, decimal_point, decimal_point_len);
 		c += decimal_point_len;
 		memcpy(c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
@@ -131,24 +158,27 @@
 		if (fail_pos)
 		{
 			if (fail_pos > decimal_point_pos)
-				fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
+				fail_pos = (char *)digits_pos +
+					(fail_pos - copy) -
+					(decimal_point_len - 1);
 			else
-				fail_pos = (char *)nptr + (fail_pos - copy);
+				fail_pos = (char *)digits_pos +
+					(fail_pos - copy);
 		}
 
 		PyMem_FREE(copy);
 
 	}
 	else {
-		unsigned i = 0;
-		if (nptr[i] == '-')
-			i++;
-		if (nptr[i] == '0' && (nptr[i+1] == 'x' || nptr[i+1] == 'X'))
-			fail_pos = (char*)nptr;
-		else
-			val = strtod(nptr, &fail_pos);
+		val = strtod(digits_pos, &fail_pos);
 	}
 
+	if (fail_pos == digits_pos)
+		fail_pos = (char *)nptr;
+
+	if (negate && fail_pos != nptr)
+		val = -val;
+
 	if (endptr)
 		*endptr = fail_pos;
 


More information about the Python-checkins mailing list