mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 21:51:50 +00:00 
			
		
		
		
	Issue #7632: Fix a serious wrong output bug for string -> float conversion.
Also remove some now unused variables, and add comments clarifying the possible outputs of the parsing section of _Py_dg_strtod. Thanks Eric Smith for reviewing.
This commit is contained in:
		
							parent
							
								
									ed44dfa4c7
								
							
						
					
					
						commit
						476279f18b
					
				
					 3 changed files with 49 additions and 19 deletions
				
			
		|  | @ -1340,7 +1340,7 @@ bigcomp(U *rv, const char *s0, BCinfo *bc) | |||
| double | ||||
| _Py_dg_strtod(const char *s00, char **se) | ||||
| { | ||||
|     int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dp0, dp1, dplen, e, e1, error; | ||||
|     int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1, error; | ||||
|     int esign, i, j, k, nd, nd0, nf, nz, nz0, sign; | ||||
|     const char *s, *s0, *s1; | ||||
|     double aadj, aadj1; | ||||
|  | @ -1349,7 +1349,7 @@ _Py_dg_strtod(const char *s00, char **se) | |||
|     BCinfo bc; | ||||
|     Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; | ||||
| 
 | ||||
|     sign = nz0 = nz = dplen = 0; | ||||
|     sign = nz0 = nz = 0; | ||||
|     dval(&rv) = 0.; | ||||
|     for(s = s00;;s++) switch(*s) { | ||||
|         case '-': | ||||
|  | @ -1388,11 +1388,8 @@ _Py_dg_strtod(const char *s00, char **se) | |||
|         else if (nd < 16) | ||||
|             z = 10*z + c - '0'; | ||||
|     nd0 = nd; | ||||
|     dp0 = dp1 = s - s0; | ||||
|     if (c == '.') { | ||||
|         c = *++s; | ||||
|         dp1 = s - s0; | ||||
|         dplen = 1; | ||||
|         if (!nd) { | ||||
|             for(; c == '0'; c = *++s) | ||||
|                 nz++; | ||||
|  | @ -1477,6 +1474,32 @@ _Py_dg_strtod(const char *s00, char **se) | |||
| 
 | ||||
|     if (!nd0) | ||||
|         nd0 = nd; | ||||
| 
 | ||||
|     /* Summary of parsing results.  The parsing stage gives values
 | ||||
|      * s0, nd0, nd, e, y and z such that: | ||||
|      * | ||||
|      *  - nd >= nd0 >= 1 | ||||
|      * | ||||
|      *  - the nd significant digits are in s0[0:nd0] and s0[nd0+1:nd+1] | ||||
|      *    (using the usual Python half-open slice notation) | ||||
|      * | ||||
|      *  - the absolute value of the number represented by the original input | ||||
|      *    string is n * 10**e, where n is the integer represented by the | ||||
|      *    concatenation of s0[0:nd0] and s0[nd0+1:nd+1] | ||||
|      * | ||||
|      *  - the first significant digit is nonzero | ||||
|      * | ||||
|      *  - the last significant digit may or may not be nonzero; (some code | ||||
|      *    currently assumes that it's nonzero; this is a bug) | ||||
|      * | ||||
|      *  - y contains the value represented by the first min(9, nd) | ||||
|      *    significant digits | ||||
|      * | ||||
|      *  - if nd > 9, z contains the value represented by significant digits | ||||
|      *    with indices in [9, min(16, nd)).  So y * 10**(min(16, nd) - 9) + z | ||||
|      *    gives the value represented by the first min(16, nd) sig. digits. | ||||
|      */ | ||||
| 
 | ||||
|     k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; | ||||
|     dval(&rv) = y; | ||||
|     if (k > 9) { | ||||
|  | @ -1593,15 +1616,18 @@ _Py_dg_strtod(const char *s00, char **se) | |||
|         /* ASSERT(STRTOD_DIGLIM >= 18); 18 == one more than the */ | ||||
|         /* minimum number of decimal digits to distinguish double values */ | ||||
|         /* in IEEE arithmetic. */ | ||||
|         i = j = 18; | ||||
|         if (i > nd0) | ||||
|             j += dplen; | ||||
|         for(;;) { | ||||
|             if (--j <= dp1 && j >= dp0) | ||||
|                 j = dp0 - 1; | ||||
|             if (s0[j] != '0') | ||||
|                 break; | ||||
| 
 | ||||
|         /* Truncate input to 18 significant digits, then discard any trailing
 | ||||
|            zeros on the result by updating nd, nd0, e and y suitably. (There's | ||||
|            no need to update z; it's not reused beyond this point.) */ | ||||
|         for (i = 18; 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; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         e += nd - i; | ||||
|         nd = i; | ||||
|  | @ -1611,8 +1637,8 @@ _Py_dg_strtod(const char *s00, char **se) | |||
|             y = 0; | ||||
|             for(i = 0; i < nd0; ++i) | ||||
|                 y = 10*y + s0[i] - '0'; | ||||
|             for(j = dp1; i < nd; ++i) | ||||
|                 y = 10*y + s0[j++] - '0'; | ||||
|             for(; i < nd; ++i) | ||||
|                 y = 10*y + s0[i+1] - '0'; | ||||
|         } | ||||
|     } | ||||
|     bd0 = s2b(s0, nd0, nd, y); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Mark Dickinson
						Mark Dickinson