[Python-checkins] r77670 - in python/branches/py3k: Lib/test/test_strtod.py Python/dtoa.c

mark.dickinson python-checkins at python.org
Thu Jan 21 20:51:08 CET 2010


Author: mark.dickinson
Date: Thu Jan 21 20:51:08 2010
New Revision: 77670

Log:
Merged revisions 77614-77616,77663 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r77614 | mark.dickinson | 2010-01-20 17:36:31 +0000 (Wed, 20 Jan 2010) | 5 lines
  
  Various dtoa.c cleanups.  1. Despagghetify _Py_dg_strtod parsing code
  and exit points.  2. Simplify bigcomp comparison loop.  3. Don't set
  ERANGE on _Py_dg_strtod underflow (it was set inconsistently anyway).
  4. Remove unused dsign field from BCinfo struct.
........
  r77615 | mark.dickinson | 2010-01-20 18:02:41 +0000 (Wed, 20 Jan 2010) | 1 line
  
  Don't try to put a value into a NULL pointer.
........
  r77616 | mark.dickinson | 2010-01-20 21:23:25 +0000 (Wed, 20 Jan 2010) | 1 line
  
  Additional explanatory comments for _Py_dg_strtod.
........
  r77663 | mark.dickinson | 2010-01-21 17:02:53 +0000 (Thu, 21 Jan 2010) | 1 line
  
  Additional testcases for strtod.
........


Modified:
   python/branches/py3k/   (props changed)
   python/branches/py3k/Lib/test/test_strtod.py
   python/branches/py3k/Python/dtoa.c

Modified: python/branches/py3k/Lib/test/test_strtod.py
==============================================================================
--- python/branches/py3k/Lib/test/test_strtod.py	(original)
+++ python/branches/py3k/Lib/test/test_strtod.py	Thu Jan 21 20:51:08 2010
@@ -100,6 +100,49 @@
                          "Incorrectly rounded str->float conversion for {}: "
                          "expected {}, got {}".format(s, expected, got))
 
+    def test_short_halfway_cases(self):
+        # exact halfway cases with a small number of significant digits
+        for k in 0, 5, 10, 15, 20:
+            # upper = smallest integer >= 2**54/5**k
+            upper = -(-2**54//5**k)
+            # lower = smallest odd number >= 2**53/5**k
+            lower = -(-2**53//5**k)
+            if lower % 2 == 0:
+                lower += 1
+            for i in range(10 * TEST_SIZE):
+                # Select a random odd n in [2**53/5**k,
+                # 2**54/5**k). Then n * 10**k gives a halfway case
+                # with small number of significant digits.
+                n, e = random.randrange(lower, upper, 2), k
+
+                # Remove any additional powers of 5.
+                while n % 5 == 0:
+                    n, e = n // 5, e + 1
+                assert n % 10 in (1, 3, 7, 9)
+
+                # Try numbers of the form n * 2**p2 * 10**e, p2 >= 0,
+                # until n * 2**p2 has more than 20 significant digits.
+                digits, exponent = n, e
+                while digits < 10**20:
+                    s = '{}e{}'.format(digits, exponent)
+                    self.check_strtod(s)
+                    # Same again, but with extra trailing zeros.
+                    s = '{}e{}'.format(digits * 10**40, exponent - 40)
+                    self.check_strtod(s)
+                    digits *= 2
+
+                # Try numbers of the form n * 5**p2 * 10**(e - p5), p5
+                # >= 0, with n * 5**p5 < 10**20.
+                digits, exponent = n, e
+                while digits < 10**20:
+                    s = '{}e{}'.format(digits, exponent)
+                    self.check_strtod(s)
+                    # Same again, but with extra trailing zeros.
+                    s = '{}e{}'.format(digits * 10**40, exponent - 40)
+                    self.check_strtod(s)
+                    digits *= 5
+                    exponent -= 1
+
     def test_halfway_cases(self):
         # test halfway cases for the round-half-to-even rule
         for i in range(1000):
@@ -164,10 +207,10 @@
                 self.check_strtod(s)
 
     def test_bigcomp(self):
-        DIG10 = 10**50
-        for i in range(1000):
-            for j in range(TEST_SIZE):
-                digits = random.randrange(DIG10)
+        for ndigs in 5, 10, 14, 15, 16, 17, 18, 19, 20, 40, 41, 50:
+            dig10 = 10**ndigs
+            for i in range(100 * TEST_SIZE):
+                digits = random.randrange(dig10)
                 exponent = random.randrange(-400, 400)
                 s = '{}e{}'.format(digits, exponent)
                 self.check_strtod(s)
@@ -254,11 +297,59 @@
             # demonstration that original fix for issue 7632 bug 1 was
             # buggy; the exit condition was too strong
             '247032822920623295e-341',
+            # demonstrate similar problem to issue 7632 bug1: crash
+            # with 'oversized quotient in quorem' message.
+            '99037485700245683102805043437346965248029601286431e-373',
+            '99617639833743863161109961162881027406769510558457e-373',
+            '98852915025769345295749278351563179840130565591462e-372',
+            '99059944827693569659153042769690930905148015876788e-373',
+            '98914979205069368270421829889078356254059760327101e-372',
             # issue 7632 bug 5: the following 2 strings convert differently
             '1000000000000000000000000000000000000000e-16',
             '10000000000000000000000000000000000000000e-17',
+            # issue 7632 bug 7
+            '991633793189150720000000000000000000000000000000000000000e-33',
+            # And another, similar, failing halfway case
+            '4106250198039490000000000000000000000000000000000000000e-38',
             # issue 7632 bug 8:  the following produced 10.0
             '10.900000000000000012345678912345678912345',
+            # exercise exit conditions in bigcomp comparison loop
+            '2602129298404963083833853479113577253105939995688e2',
+            '260212929840496308383385347911357725310593999568896e0',
+            '26021292984049630838338534791135772531059399956889601e-2',
+            '260212929840496308383385347911357725310593999568895e0',
+            '260212929840496308383385347911357725310593999568897e0',
+            '260212929840496308383385347911357725310593999568996e0',
+            '260212929840496308383385347911357725310593999568866e0',
+            # 2**53
+            '9007199254740992.00',
+            # 2**1024 - 2**970:  exact overflow boundary.  All values
+            # smaller than this should round to something finite;  any value
+            # greater than or equal to this one overflows.
+            '179769313486231580793728971405303415079934132710037' #...
+            '826936173778980444968292764750946649017977587207096' #...
+            '330286416692887910946555547851940402630657488671505' #...
+            '820681908902000708383676273854845817711531764475730' #...
+            '270069855571366959622842914819860834936475292719074' #...
+            '168444365510704342711559699508093042880177904174497792',
+            # 2**1024 - 2**970 - tiny
+            '179769313486231580793728971405303415079934132710037' #...
+            '826936173778980444968292764750946649017977587207096' #...
+            '330286416692887910946555547851940402630657488671505' #...
+            '820681908902000708383676273854845817711531764475730' #...
+            '270069855571366959622842914819860834936475292719074' #...
+            '168444365510704342711559699508093042880177904174497791.999',
+            # 2**1024 - 2**970 + tiny
+            '179769313486231580793728971405303415079934132710037' #...
+            '826936173778980444968292764750946649017977587207096' #...
+            '330286416692887910946555547851940402630657488671505' #...
+            '820681908902000708383676273854845817711531764475730' #...
+            '270069855571366959622842914819860834936475292719074' #...
+            '168444365510704342711559699508093042880177904174497792.001',
+            # 1 - 2**-54, +-tiny
+            '999999999999999944488848768742172978818416595458984375e-54',
+            '9999999999999999444888487687421729788184165954589843749999999e-54',
+            '9999999999999999444888487687421729788184165954589843750000001e-54',
             ]
         for s in test_strings:
             self.check_strtod(s)

Modified: python/branches/py3k/Python/dtoa.c
==============================================================================
--- python/branches/py3k/Python/dtoa.c	(original)
+++ python/branches/py3k/Python/dtoa.c	Thu Jan 21 20:51:08 2010
@@ -270,7 +270,7 @@
 typedef struct BCinfo BCinfo;
 struct
 BCinfo {
-    int dsign, e0, nd, nd0, scale;
+    int e0, nd, nd0, scale;
 };
 
 #define FFFFFFFF 0xffffffffUL
@@ -967,8 +967,8 @@
     return c;
 }
 
-/* Given a positive normal double x, return the difference between x and the next
-   double up.  Doesn't give correct results for subnormals. */
+/* Given a positive normal double x, return the difference between x and the
+   next double up.  Doesn't give correct results for subnormals. */
 
 static double
 ulp(U *x)
@@ -1276,9 +1276,6 @@
      bc is a struct containing information gathered during the parsing and
         estimation steps of _Py_dg_strtod.  Description of fields follows:
 
-        bc->dsign is 1 if rv < decimal value, 0 if rv >= decimal value.  In
-           normal use, it should almost always be 1 when bigcomp is entered.
-
         bc->e0 gives the exponent of the input value, such that dv = (integer
            given by the bd->nd digits of s0) * 10**e0
 
@@ -1387,47 +1384,37 @@
         }
     }
 
-    /* if b >= d, round down */
-    if (cmp(b, d) >= 0) {
+    /* Compare s0 with b/d: set dd to -1, 0, or 1 according as s0 < b/d, s0 ==
+     * b/d, or s0 > b/d.  Here the digits of s0 are thought of as representing
+     * a number in the range [0.1, 1). */
+    if (cmp(b, d) >= 0)
+        /* b/d >= 1 */
         dd = -1;
-        goto ret;
-    }
+    else {
+        i = 0;
+        for(;;) {
+            b = multadd(b, 10, 0);
+            if (b == NULL) {
+                Bfree(d);
+                return -1;
+            }
+            dd = s0[i < nd0 ? i : i+1] - '0' - quorem(b, d);
+            i++;
 
-    /* Compare b/d with s0 */
-    for(i = 0; i < nd0; i++) {
-        b = multadd(b, 10, 0);
-        if (b == NULL) {
-            Bfree(d);
-            return -1;
-        }
-        dd = *s0++ - '0' - quorem(b, d);
-        if (dd)
-            goto ret;
-        if (!b->x[0] && b->wds == 1) {
-            if (i < nd - 1)
-                dd = 1;
-            goto ret;
-        }
-    }
-    s0++;
-    for(; i < nd; i++) {
-        b = multadd(b, 10, 0);
-        if (b == NULL) {
-            Bfree(d);
-            return -1;
-        }
-        dd = *s0++ - '0' - quorem(b, d);
-        if (dd)
-            goto ret;
-        if (!b->x[0] && b->wds == 1) {
-            if (i < nd - 1)
-                dd = 1;
-            goto ret;
+            if (dd)
+                break;
+            if (!b->x[0] && b->wds == 1) {
+                /* b/d == 0 */
+                dd = i < nd;
+                break;
+            }
+            if (!(i < nd)) {
+                /* b/d != 0, but digits of s0 exhausted */
+                dd = -1;
+                break;
+            }
         }
     }
-    if (b->x[0] || b->wds > 1)
-        dd = -1;
-  ret:
     Bfree(b);
     Bfree(d);
     if (dd > 0 || (dd == 0 && odd))
@@ -1438,128 +1425,130 @@
 double
 _Py_dg_strtod(const char *s00, char **se)
 {
-    int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1, error;
-    int esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
+    int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, e, e1, error;
+    int esign, i, j, k, lz, nd, nd0, sign;
     const char *s, *s0, *s1;
     double aadj, aadj1;
     U aadj2, adj, rv, rv0;
-    ULong y, z, abse;
+    ULong y, z, abs_exp;
     Long L;
     BCinfo bc;
     Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
 
-    sign = nz0 = nz = 0;
     dval(&rv) = 0.;
-    for(s = s00;;s++) switch(*s) {
-        case '-':
-            sign = 1;
-            /* no break */
-        case '+':
-            if (*++s)
-                goto break2;
-            /* no break */
-        case 0:
-            goto ret0;
-        /* modify original dtoa.c so that it doesn't accept leading whitespace
-        case '\t':
-        case '\n':
-        case '\v':
-        case '\f':
-        case '\r':
-        case ' ':
-            continue;
-        */
-        default:
-            goto break2;
-        }
-  break2:
-    if (*s == '0') {
-        nz0 = 1;
-        while(*++s == '0') ;
-        if (!*s)
-            goto ret;
+
+    /* Start parsing. */
+    c = *(s = s00);
+
+    /* Parse optional sign, if present. */
+    sign = 0;
+    switch (c) {
+    case '-':
+        sign = 1;
+        /* no break */
+    case '+':
+        c = *++s;
     }
-    s0 = s;
-    for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
-        ;
-    nd0 = nd;
+
+    /* Skip leading zeros: lz is true iff there were leading zeros. */
+    s1 = s;
+    while (c == '0')
+        c = *++s;
+    lz = s != s1;
+
+    /* Point s0 at the first nonzero digit (if any).  nd0 will be the position
+       of the point relative to s0.  nd will be the total number of digits
+       ignoring leading zeros. */
+    s0 = s1 = s;
+    while ('0' <= c && c <= '9')
+        c = *++s;
+    nd0 = nd = s - s1;
+
+    /* Parse decimal point and following digits. */
     if (c == '.') {
         c = *++s;
         if (!nd) {
-            for(; c == '0'; c = *++s)
-                nz++;
-            if (c > '0' && c <= '9') {
-                s0 = s;
-                nf += nz;
-                nz = 0;
-                goto have_dig;
-            }
-            goto dig_done;
-        }
-        for(; c >= '0' && c <= '9'; c = *++s) {
-          have_dig:
-            nz++;
-            if (c -= '0') {
-                nf += nz;
-                nd += nz;
-                nz = 0;
-            }
+            s1 = s;
+            while (c == '0')
+                c = *++s;
+            lz = lz || s != s1;
+            nd0 -= s - s1;
+            s0 = s;
         }
+        s1 = s;
+        while ('0' <= c && c <= '9')
+            c = *++s;
+        nd += s - s1;
+    }
+
+    /* Now lz is true if and only if there were leading zero digits, and nd
+       gives the total number of digits ignoring leading zeros.  A valid input
+       must have at least one digit. */
+    if (!nd && !lz) {
+        if (se)
+            *se = (char *)s00;
+        goto parse_error;
     }
-  dig_done:
+
+    /* Parse exponent. */
     e = 0;
     if (c == 'e' || c == 'E') {
-        if (!nd && !nz && !nz0) {
-            goto ret0;
-        }
         s00 = s;
+        c = *++s;
+
+        /* Exponent sign. */
         esign = 0;
-        switch(c = *++s) {
+        switch (c) {
         case '-':
             esign = 1;
+            /* no break */
         case '+':
             c = *++s;
         }
-        if (c >= '0' && c <= '9') {
-            while(c == '0')
-                c = *++s;
-            if (c > '0' && c <= '9') {
-                abse = c - '0';
-                s1 = s;
-                while((c = *++s) >= '0' && c <= '9')
-                    abse = 10*abse + c - '0';
-                if (s - s1 > 8 || abse > MAX_ABS_EXP)
-                    /* Avoid confusion from exponents
-                     * so large that e might overflow.
-                     */
-                    e = (int)MAX_ABS_EXP; /* safe for 16 bit ints */
-                else
-                    e = (int)abse;
-                if (esign)
-                    e = -e;
-            }
-            else
-                e = 0;
+
+        /* Skip zeros.  lz is true iff there are leading zeros. */
+        s1 = s;
+        while (c == '0')
+            c = *++s;
+        lz = s != s1;
+
+        /* Get absolute value of the exponent. */
+        s1 = s;
+        abs_exp = 0;
+        while ('0' <= c && c <= '9') {
+            abs_exp = 10*abs_exp + (c - '0');
+            c = *++s;
         }
+
+        /* abs_exp will be correct modulo 2**32.  But 10**9 < 2**32, so if
+           there are at most 9 significant exponent digits then overflow is
+           impossible. */
+        if (s - s1 > 9 || abs_exp > MAX_ABS_EXP)
+            e = (int)MAX_ABS_EXP;
         else
+            e = (int)abs_exp;
+        if (esign)
+            e = -e;
+
+        /* A valid exponent must have at least one digit. */
+        if (s == s1 && !lz)
             s = s00;
     }
-    if (!nd) {
-        if (!nz && !nz0) {
-          ret0:
-            s = s00;
-            sign = 0;
-        }
-        goto ret;
-    }
-    e -= nf;
-    if (!nd0)
+
+    /* Adjust exponent to take into account position of the point. */
+    e -= nd - nd0;
+    if (nd0 <= 0)
         nd0 = nd;
 
-    /* strip trailing zeros */
+    /* Finished parsing.  Set se to indicate how far we parsed */
+    if (se)
+        *se = (char *)s;
+
+    /* If all digits were zero, exit with return value +-0.0.  Otherwise,
+       strip trailing zeros: scan back until we hit a nonzero digit. */
+    if (!nd)
+        goto ret;
     for (i = nd; i > 0; ) {
-        /* scan back until we hit a nonzero digit.  significant digit 'i'
-           is s0[i] if i < nd0, s0[i+1] if i >= nd0. */
         --i;
         if (s0[i < nd0 ? i : i+1] != '0') {
             ++i;
@@ -1571,28 +1560,21 @@
     if (nd0 > nd)
         nd0 = nd;
 
-    /* Now we have nd0 digits, starting at s0, followed by a
-     * decimal point, followed by nd-nd0 digits.  The number we're
-     * after is the integer represented by those digits times
-     * 10**e */
-
-    bc.e0 = e1 = e;
-
-    /* Summary of parsing results.  The parsing stage gives values
-     * s0, nd0, nd, e, sign, where:
+    /* Summary of parsing results.  After parsing, and dealing with zero
+     * inputs, we have values s0, nd0, nd, e, sign, where:
      *
-     *  - s0 points to the first significant digit of the input string s00;
+     *  - s0 points to the first significant digit of the input string
      *
      *  - nd is the total number of significant digits (here, and
      *    below, 'significant digits' means the set of digits of the
      *    significand of the input that remain after ignoring leading
-     *    and trailing zeros.
+     *    and trailing zeros).
      *
-     *  - nd0 indicates the position of the decimal point (if
-     *    present): so the nd significant digits are in s0[0:nd0] and
-     *    s0[nd0+1:nd+1] using the usual Python half-open slice
-     *    notation.  (If nd0 < nd, then s0[nd0] necessarily contains
-     *    a '.' character;  if nd0 == nd, then it could be anything.)
+     *  - nd0 indicates the position of the decimal point, if present; it
+     *    satisfies 1 <= nd0 <= nd.  The nd significant digits are in
+     *    s0[0:nd0] and s0[nd0+1:nd+1] using the usual Python half-open slice
+     *    notation.  (If nd0 < nd, then s0[nd0] contains a '.'  character; if
+     *    nd0 == nd, then s0[nd0] could be any non-digit character.)
      *
      *  - e is the adjusted exponent: the absolute value of the number
      *    represented by the original input string is n * 10**e, where
@@ -1614,6 +1596,7 @@
      *    gives the value represented by the first min(16, nd) sig. digits.
      */
 
+    bc.e0 = e1 = e;
     y = z = 0;
     for (i = 0; i < nd; i++) {
         if (i < 9)
@@ -1666,14 +1649,8 @@
         if ((i = e1 & 15))
             dval(&rv) *= tens[i];
         if (e1 &= ~15) {
-            if (e1 > DBL_MAX_10_EXP) {
-              ovfl:
-                errno = ERANGE;
-                /* Can't trust HUGE_VAL */
-                word0(&rv) = Exp_mask;
-                word1(&rv) = 0;
-                goto ret;
-            }
+            if (e1 > DBL_MAX_10_EXP)
+                goto ovfl;
             e1 >>= 4;
             for(j = 0; e1 > 1; j++, e1 >>= 1)
                 if (e1 & 1)
@@ -1695,6 +1672,16 @@
         }
     }
     else if (e1 < 0) {
+        /* The input decimal value lies in [10**e1, 10**(e1+16)).
+
+           If e1 <= -512, underflow immediately.
+           If e1 <= -256, set bc.scale to 2*P.
+
+           So for input value < 1e-256, bc.scale is always set;
+           for input value >= 1e-240, bc.scale is never set.
+           For input values in [1e-256, 1e-240), bc.scale may or may
+           not be set. */
+
         e1 = -e1;
         if ((i = e1 & 15))
             dval(&rv) /= tens[i];
@@ -1719,12 +1706,8 @@
                 else
                     word1(&rv) &= 0xffffffff << j;
             }
-            if (!dval(&rv)) {
-              undfl:
-                dval(&rv) = 0.;
-                errno = ERANGE;
-                goto ret;
-            }
+            if (!dval(&rv))
+                goto undfl;
         }
     }
 
@@ -1769,7 +1752,34 @@
     if (bd0 == NULL)
         goto failed_malloc;
 
+    /* Notation for the comments below.  Write:
+
+         - dv for the absolute value of the number represented by the original
+           decimal input string.
+
+         - if we've truncated dv, write tdv for the truncated value.
+           Otherwise, set tdv == dv.
+
+         - srv for the quantity rv/2^bc.scale; so srv is the current binary
+           approximation to tdv (and dv).  It should be exactly representable
+           in an IEEE 754 double.
+    */
+
     for(;;) {
+
+        /* This is the main correction loop for _Py_dg_strtod.
+
+           We've got a decimal value tdv, and a floating-point approximation
+           srv=rv/2^bc.scale to tdv.  The aim is to determine whether srv is
+           close enough (i.e., within 0.5 ulps) to tdv, and to compute a new
+           approximation if not.
+
+           To determine whether srv is close enough to tdv, compute integers
+           bd, bb and bs proportional to tdv, srv and 0.5 ulp(srv)
+           respectively, and then use integer arithmetic to determine whether
+           |tdv - srv| is less than, equal to, or greater than 0.5 ulp(srv).
+        */
+
         bd = Balloc(bd0->k);
         if (bd == NULL) {
             Bfree(bd0);
@@ -1782,6 +1792,7 @@
             Bfree(bd0);
             goto failed_malloc;
         }
+        /* tdv = bd * 10^e;  srv = bb * 2^(bbe - scale) */
         bs = i2b(1);
         if (bs == NULL) {
             Bfree(bb);
@@ -1802,6 +1813,17 @@
             bb2 += bbe;
         else
             bd2 -= bbe;
+
+        /* At this stage e = bd2 - bb2 + bbe = bd5 - bb5, so:
+
+              tdv = bd * 2^(bbe + bd2 - bb2) * 5^(bd5 - bb5)
+              srv = bb * 2^(bbe - scale).
+
+           Compute j such that
+
+              0.5 ulp(srv) = 2^(bbe - scale - j)
+        */
+
         bs2 = bb2;
         j = bbe - bc.scale;
         i = j + bbbits - 1;     /* logb(rv) */
@@ -1809,9 +1831,26 @@
             j += P - Emin;
         else
             j = P + 1 - bbbits;
+
+       /* Now we have:
+
+              M * tdv = bd * 2^(bd2 + scale + j) * 5^bd5
+              M * srv = bb * 2^(bb2 + j) * 5^bb5
+              M * 0.5 ulp(srv) = 2^bs2 * 5^bb5
+
+           where M is the constant (currently) represented by 2^(j + scale +
+           bb2 - bbe) * 5^bb5.
+        */
+
         bb2 += j;
         bd2 += j;
         bd2 += bc.scale;
+
+        /* After the adjustments above, tdv, srv and 0.5 ulp(srv) are
+           proportional to: bd * 2^bd2 * 5^bd5, bb * 2^bb2 * 5^bb5, and
+           bs * 2^bs2 * 5^bb5, respectively. */
+
+        /* Remove excess powers of 2. i = min(bb2, bd2, bs2). */
         i = bb2 < bd2 ? bb2 : bd2;
         if (i > bs2)
             i = bs2;
@@ -1820,6 +1859,8 @@
             bd2 -= i;
             bs2 -= i;
         }
+
+        /* Scale bb, bd, bs by the appropriate powers of 2 and 5. */
         if (bb5 > 0) {
             bs = pow5mult(bs, bb5);
             if (bs == NULL) {
@@ -1874,6 +1915,11 @@
                 goto failed_malloc;
             }
         }
+
+        /* Now bd, bb and bs are scaled versions of tdv, srv and 0.5 ulp(srv),
+           respectively.  Compute the difference |tdv - srv|, and compare
+           with 0.5 ulp(srv). */
+
         delta = diff(bb, bd);
         if (delta == NULL) {
             Bfree(bb);
@@ -1882,11 +1928,11 @@
             Bfree(bd0);
             goto failed_malloc;
         }
-        bc.dsign = delta->sign;
+        dsign = delta->sign;
         delta->sign = 0;
         i = cmp(delta, bs);
         if (bc.nd > nd && i <= 0) {
-            if (bc.dsign)
+            if (dsign)
                 break;  /* Must use bigcomp(). */
 
             /* Here rv overestimates the truncated decimal value by at most
@@ -1908,7 +1954,7 @@
                    rv / 2^bc.scale >= 2^-1021. */
                 if (j - bc.scale >= 2) {
                     dval(&rv) -= 0.5 * sulp(&rv, &bc);
-                    break;
+                    break; /* Use bigcomp. */
                 }
             }
 
@@ -1922,7 +1968,7 @@
             /* Error is less than half an ulp -- check for
              * special case of mantissa a power of two.
              */
-            if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask
+            if (dsign || word1(&rv) || word0(&rv) & Bndry_mask
                 || (word0(&rv) & Exp_mask) <= (2*P+1)*Exp_msk1
                 ) {
                 break;
@@ -1945,7 +1991,7 @@
         }
         if (i == 0) {
             /* exactly half-way between */
-            if (bc.dsign) {
+            if (dsign) {
                 if ((word0(&rv) & Bndry_mask1) == Bndry_mask1
                     &&  word1(&rv) == (
                         (bc.scale &&
@@ -1957,7 +2003,7 @@
                         + Exp_msk1
                         ;
                     word1(&rv) = 0;
-                    bc.dsign = 0;
+                    dsign = 0;
                     break;
                 }
             }
@@ -1972,7 +2018,7 @@
                             /* accept rv */
                             break;
                         /* rv = smallest denormal */
-                        if (bc.nd >nd)
+                        if (bc.nd > nd)
                             break;
                         goto undfl;
                     }
@@ -1984,7 +2030,7 @@
             }
             if (!(word1(&rv) & LSB))
                 break;
-            if (bc.dsign)
+            if (dsign)
                 dval(&rv) += ulp(&rv);
             else {
                 dval(&rv) -= ulp(&rv);
@@ -1994,11 +2040,11 @@
                     goto undfl;
                 }
             }
-            bc.dsign = 1 - bc.dsign;
+            dsign = 1 - dsign;
             break;
         }
         if ((aadj = ratio(delta, bs)) <= 2.) {
-            if (bc.dsign)
+            if (dsign)
                 aadj = aadj1 = 1.;
             else if (word1(&rv) || word0(&rv) & Bndry_mask) {
                 if (word1(&rv) == Tiny1 && !word0(&rv)) {
@@ -2022,7 +2068,7 @@
         }
         else {
             aadj *= 0.5;
-            aadj1 = bc.dsign ? aadj : -aadj;
+            aadj1 = dsign ? aadj : -aadj;
             if (Flt_Rounds == 0)
                 aadj1 += 0.5;
         }
@@ -2058,7 +2104,7 @@
                     if ((z = (ULong)aadj) <= 0)
                         z = 1;
                     aadj = z;
-                    aadj1 = bc.dsign ? aadj : -aadj;
+                    aadj1 = dsign ? aadj : -aadj;
                 }
                 dval(&aadj2) = aadj1;
                 word0(&aadj2) += (2*P+1)*Exp_msk1 - y;
@@ -2075,7 +2121,7 @@
                     L = (Long)aadj;
                     aadj -= L;
                     /* The tolerances below are conservative. */
-                    if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask) {
+                    if (dsign || word1(&rv) || word0(&rv) & Bndry_mask) {
                         if (aadj < .4999999 || aadj > .5000001)
                             break;
                     }
@@ -2104,20 +2150,28 @@
         word0(&rv0) = Exp_1 - 2*P*Exp_msk1;
         word1(&rv0) = 0;
         dval(&rv) *= dval(&rv0);
-        /* try to avoid the bug of testing an 8087 register value */
-        if (!(word0(&rv) & Exp_mask))
-            errno = ERANGE;
     }
+
   ret:
-    if (se)
-        *se = (char *)s;
     return sign ? -dval(&rv) : dval(&rv);
 
+  parse_error:
+    return 0.0;
+
   failed_malloc:
-    if (se)
-        *se = (char *)s00;
     errno = ENOMEM;
     return -1.0;
+
+  undfl:
+    return sign ? -0.0 : 0.0;
+
+  ovfl:
+    errno = ERANGE;
+    /* Can't trust HUGE_VAL */
+    word0(&rv) = Exp_mask;
+    word1(&rv) = 0;
+    return sign ? -dval(&rv) : dval(&rv);
+
 }
 
 static char *


More information about the Python-checkins mailing list