]> granicus.if.org Git - python/commitdiff
Merged revisions 72564 via svnmerge from
authorMark Dickinson <dickinsm@gmail.com>
Mon, 11 May 2009 16:09:39 +0000 (16:09 +0000)
committerMark Dickinson <dickinsm@gmail.com>
Mon, 11 May 2009 16:09:39 +0000 (16:09 +0000)
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.
........

Lib/test/test_float.py
Misc/NEWS
Objects/floatobject.c

index 0b1ae96495bc9c27a3cf0ae7cab8398b6ee22ddd..23c0c540bf91eeb4e50422982e1f8f7e2132d35a 100644 (file)
@@ -391,6 +391,11 @@ class HexFloatTestCase(unittest.TestCase):
             'snan',
             'NaNs',
             'nna',
+            'an',
+            'nf',
+            'nfinity',
+            'inity',
+            'iinity',
             '0xnan',
             '',
             ' ',
@@ -439,6 +444,32 @@ class HexFloatTestCase(unittest.TestCase):
                           '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;
index a068c5e2d8341ec10a5899cbb614521c1f1c5b19..43e6024585725d0a572aaea597e2cadfe0b93089 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,11 @@ What's New in Python 2.6.3
 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__.
index 4f041f4820cce51d28dff0ec63ac85ceff515c7d..2d00c16d9c5ecd125279a91cafc4a1adfed816ee 100644 (file)
@@ -1263,6 +1263,20 @@ Return a hexadecimal representation of a floating-point number.\n\
 >>> 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 @@ float_fromhex(PyObject *cls, PyObject *arg)
         ********************/
 
        /* leading whitespace and optional sign */
-       while (isspace(*s))
+       while (*s && isspace(Py_CHARMASK(*s)))
                s++;
        if (*s == '-') {
                s++;
@@ -1339,13 +1353,20 @@ float_fromhex(PyObject *cls, PyObject *arg)
                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 @@ float_fromhex(PyObject *cls, PyObject *arg)
        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 @@ float_fromhex(PyObject *cls, PyObject *arg)
        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 @@ float_fromhex(PyObject *cls, PyObject *arg)
 
        /* 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 @@ float_fromhex(PyObject *cls, PyObject *arg)
                /* 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 @@ float_fromhex(PyObject *cls, PyObject *arg)
                                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);