]> granicus.if.org Git - python/commitdiff
Merged revisions 72564 via svnmerge from
authorMark Dickinson <dickinsm@gmail.com>
Mon, 11 May 2009 15:45:15 +0000 (15:45 +0000)
committerMark Dickinson <dickinsm@gmail.com>
Mon, 11 May 2009 15:45:15 +0000 (15:45 +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 c259d4f3be746549a532c9a472f19e409374991d..b4b62f0445d168d4070a6372e31500d026d2211c 100644 (file)
@@ -615,6 +615,11 @@ class HexFloatTestCase(unittest.TestCase):
             'snan',
             'NaNs',
             'nna',
+            'an',
+            'nf',
+            'nfinity',
+            'inity',
+            'iinity',
             '0xnan',
             '',
             ' ',
@@ -663,6 +668,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 c531f1e42d0fd65c3ed3027c307c7448869dc80e..9a5e441e5417caf6402eb126c64c76286f18b08f 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,12 @@ What's New in Python 3.1 release candiate 1?
 Core and Builtins
 -----------------
 
+- Issue #5981: Fix three minor inf/nan issues in float.fromhex:
+  (1) inf and nan strings with trailing whitespace were incorrectly
+  rejected;  (2) parsing of strings representing infinities and nans
+  was locale aware; and (3) the interpretation of fromhex('-nan')
+  didn't match that of float('-nan').
+
 Library
 -------
 
index 1074f3d0fd5f67572b7bf250cca643d532967284..cd8c14fb2d5174c87ea74487c9287d848d54c470 100644 (file)
@@ -1157,6 +1157,20 @@ Return a hexadecimal representation of a floating-point number.\n\
 >>> 3.14159.hex()\n\
 '0x1.921f9f01b866ep+1'");
 
+/* Case-insensitive locale-independent 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 && Py_TOLOWER(*s) == *t) {
+               s++;
+               t++;
+       }
+       return *t ? 0 : 1;
+}
+
 /* Convert a hexadecimal string to a float. */
 
 static PyObject *
@@ -1234,13 +1248,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;
        }
 
@@ -1293,12 +1314,6 @@ float_fromhex(PyObject *cls, PyObject *arg)
        else
                exp = 0;
 
-       /* optional trailing whitespace leading to the end of the string */
-       while (Py_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) :                    \
@@ -1312,7 +1327,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)
@@ -1328,7 +1343,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)
@@ -1343,7 +1358,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
@@ -1377,10 +1392,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 (Py_ISSPACE(*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);