[Python-checkins] r72566 - in python/branches/release26-maint: Lib/test/test_float.py Misc/NEWS Objects/floatobject.c

mark.dickinson python-checkins at python.org
Mon May 11 18:09:39 CEST 2009


Author: mark.dickinson
Date: Mon May 11 18:09:39 2009
New Revision: 72566

Log:
Merged revisions 72564 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r72564 | mark.dickinson | 2009-05-11 16:33:08 +0100 (Mon, 11 May 2009) | 2 lines
  
  Issue #5981: Fix some float.fromhex bugs related to inf and nan handling.
........


Modified:
   python/branches/release26-maint/   (props changed)
   python/branches/release26-maint/Lib/test/test_float.py
   python/branches/release26-maint/Misc/NEWS
   python/branches/release26-maint/Objects/floatobject.c

Modified: python/branches/release26-maint/Lib/test/test_float.py
==============================================================================
--- python/branches/release26-maint/Lib/test/test_float.py	(original)
+++ python/branches/release26-maint/Lib/test/test_float.py	Mon May 11 18:09:39 2009
@@ -391,6 +391,11 @@
             'snan',
             'NaNs',
             'nna',
+            'an',
+            'nf',
+            'nfinity',
+            'inity',
+            'iinity',
             '0xnan',
             '',
             ' ',
@@ -439,6 +444,32 @@
                           'got %r instead' % (x, result))
 
 
+    def test_whitespace(self):
+        value_pairs = [
+            ('inf', INF),
+            ('-Infinity', -INF),
+            ('nan', NAN),
+            ('1.0', 1.0),
+            ('-0x.2', -0.125),
+            ('-0.0', -0.0)
+            ]
+        whitespace = [
+            '',
+            ' ',
+            '\t',
+            '\n',
+            '\n \t',
+            '\f',
+            '\v',
+            '\r'
+            ]
+        for inp, expected in value_pairs:
+            for lead in whitespace:
+                for trail in whitespace:
+                    got = fromHex(lead + inp + trail)
+                    self.identical(got, expected)
+
+
     def test_from_hex(self):
         MIN = self.MIN;
         MAX = self.MAX;

Modified: python/branches/release26-maint/Misc/NEWS
==============================================================================
--- python/branches/release26-maint/Misc/NEWS	(original)
+++ python/branches/release26-maint/Misc/NEWS	Mon May 11 18:09:39 2009
@@ -12,6 +12,11 @@
 Core and Builtins
 -----------------
 
+- Issue #5981: Fix two minor inf/nan issues in float.fromhex: (1) inf
+  and nan strings with trailing whitespace were incorrectly rejected
+  and (2) the interpretation of fromhex('-nan') didn't match that of
+  float('-nan').
+
 - Issue #5890: in subclasses of 'property' the __doc__ attribute was
   shadowed by classtype's, even if it was None.  property now
   inserts the __doc__ into the subclass instance __dict__.

Modified: python/branches/release26-maint/Objects/floatobject.c
==============================================================================
--- python/branches/release26-maint/Objects/floatobject.c	(original)
+++ python/branches/release26-maint/Objects/floatobject.c	Mon May 11 18:09:39 2009
@@ -1263,6 +1263,20 @@
 >>> 3.14159.hex()\n\
 '0x1.921f9f01b866ep+1'");
 
+/* Case-insensitive string match used for nan and inf detection. t should be
+   lower-case and null-terminated.  Return a nonzero result if the first
+   strlen(t) characters of s match t and 0 otherwise. */
+
+static int
+case_insensitive_match(const char *s, const char *t)
+{
+	while(*t && tolower(*s) == *t) {
+		s++;
+		t++;
+	}
+	return *t ? 0 : 1;
+}
+
 /* Convert a hexadecimal string to a float. */
 
 static PyObject *
@@ -1329,7 +1343,7 @@
 	 ********************/
 
 	/* leading whitespace and optional sign */
-	while (isspace(*s))
+	while (*s && isspace(Py_CHARMASK(*s)))
 		s++;
 	if (*s == '-') {
 		s++;
@@ -1339,13 +1353,20 @@
 		s++;
 
 	/* infinities and nans */
-	if (PyOS_strnicmp(s, "nan", 4) == 0) {
-		x = Py_NAN;
+	if (*s == 'i' || *s == 'I') {
+		if (!case_insensitive_match(s+1, "nf"))
+			goto parse_error;
+		s += 3;
+		x = Py_HUGE_VAL;
+		if (case_insensitive_match(s, "inity"))
+			s += 5;
 		goto finished;
 	}
-	if (PyOS_strnicmp(s, "inf", 4) == 0 ||
-	    PyOS_strnicmp(s, "infinity", 9) == 0) {
-		x = sign*Py_HUGE_VAL;
+	if (*s == 'n' || *s == 'N') {
+		if (!case_insensitive_match(s+1, "an"))
+			goto parse_error;
+		s += 3;
+		x = Py_NAN;
 		goto finished;
 	}
 
@@ -1398,12 +1419,6 @@
 	else
 		exp = 0;
 
-	/* optional trailing whitespace leading to the end of the string */
-	while (isspace(*s))
-		s++;
-	if (s != s_end)
-		goto parse_error;
-
 /* for 0 <= j < ndigits, HEX_DIGIT(j) gives the jth most significant digit */
 #define HEX_DIGIT(j) hex_from_char(*((j) < fdigits ?		\
 				     coeff_end-(j) :			\
@@ -1417,7 +1432,7 @@
 	while (ndigits > 0 && HEX_DIGIT(ndigits-1) == 0)
 		ndigits--;
 	if (ndigits == 0 || exp < LONG_MIN/2) {
-		x = sign * 0.0;
+		x = 0.0;
 		goto finished;
 	}
 	if (exp > LONG_MAX/2)
@@ -1433,7 +1448,7 @@
 
 	/* catch almost all nonextreme cases of overflow and underflow here */
 	if (top_exp < DBL_MIN_EXP - DBL_MANT_DIG) {
-		x = sign * 0.0;
+		x = 0.0;
 		goto finished;
 	}
 	if (top_exp > DBL_MAX_EXP)
@@ -1448,7 +1463,7 @@
 		/* no rounding required */
 		for (i = ndigits-1; i >= 0; i--)
 			x = 16.0*x + HEX_DIGIT(i);
-		x = sign * ldexp(x, (int)(exp));
+		x = ldexp(x, (int)(exp));
 		goto finished;
 	}
 	/* rounding required.  key_digit is the index of the hex digit
@@ -1482,10 +1497,15 @@
 				goto overflow_error;
 		}
 	}
-	x = sign * ldexp(x, (int)(exp+4*key_digit));
+	x = ldexp(x, (int)(exp+4*key_digit));
 
   finished:
-	result_as_float = Py_BuildValue("(d)", x);
+	/* optional trailing whitespace leading to the end of the string */
+	while (*s && isspace(Py_CHARMASK(*s)))
+		s++;
+	if (s != s_end)
+		goto parse_error;
+	result_as_float = Py_BuildValue("(d)", sign * x);
 	if (result_as_float == NULL)
 		return NULL;
 	result = PyObject_CallObject(cls, result_as_float);


More information about the Python-checkins mailing list