@@ -932,55 +932,46 @@ char * PyOS_double_to_string(double val,
932932
933933/* _Py_dg_dtoa is available. */ 
934934
935- /* turn ASCII hex characters into integer values and vice versa */ 
936- 
937- static  char 
938- char_from_hex (int  x , int  upper )
939- {
940-     assert (0  <= x  &&  x  <  16 );
941-     char  c  =  Py_hexdigits [x ];
942-     if  (upper ) {
943-         c  =  Py_TOUPPER (c );
944-     }
945-     return  c ;
946- }
947- 
948935/* convert a float to a hexadecimal string */ 
949936
950- /* TOHEX_NBITS is DBL_MANT_DIG rounded up to the next integer 
951-    of the form 4k+1. */ 
952- #define  TOHEX_NBITS  DBL_MANT_DIG + 3 - (DBL_MANT_DIG+2)%4
953- 
954937char  * 
955938_Py_dg_dtoa_hex (double  x , int  precision , int  always_add_sign ,
956939                int  use_alt_formatting , int  upper )
957940{
958-     int  e ,  shift ,  i ,  si ;
941+     int  e ;
959942    double  m  =  frexp (fabs (x ), & e );
960943
944+     if  (precision  <  0 ) {
945+         precision  =  (DBL_MANT_DIG  +  2  -  (DBL_MANT_DIG + 2 )%4 )/4 ;
946+     }
947+ 
961948    if  (m ) {
962-         /* normalization XXX: valid after rounding?  */ 
963-         shift  =  1  -  Py_MAX (DBL_MIN_EXP  -  e , 0 );
949+         /* normalization */ 
950+         int   shift  =  1  -  Py_MAX (DBL_MIN_EXP  -  e , 0 );
964951        m  =  ldexp (m , shift );
965952        e  -=  shift ;
966-     }
967953
968-     if  (precision  <  0 ) {
969-         precision  =  (TOHEX_NBITS - 1 )/4 ;
954+         do  {
955+             /* round to precision digits */ 
956+             double  frac  =  ldexp (m , 4 * precision );
957+             frac  -=  floor (frac );
958+             frac  *= 16.0 ;
959+             m  +=  ldexp (frac  >= 8.0 , -4 * precision );
960+             if  ((int )(m ) &  0x2 ) {
961+                 m  /= 2.0 ;
962+                 e  +=  1 ;
963+             }
964+             else  {
965+                 break ;
966+             }
967+         } while  (1 );
970968    }
971969
972-     /* round to precision digits */ 
973-     double  frac  =  ldexp (m , 4 * precision );
974-     frac  -=  floor (frac );
975-     frac  *= 16.0 ;
976-     m  +=  ldexp (frac  >= 8.0 , -4 * precision );
977- 
978-     /* Space for precision + 1 digits, sign, 0x prefix, a decimal 
979-        point, the trailing NUL byte and an exponent. */ 
980-     char  * s  =  PyMem_Malloc (precision  +  DBL_MAX_EXP  +  7 );
970+     /* Allocate space for [±] 0x   h.  [hhhhhhhh]  p±  exp          '\0' */ 
971+     char  * s  =  PyMem_Malloc (1  +  2  +  2  +  precision  +  2  +  DBL_MAX_EXP  +  1 );
981972
982973    /* sign and prefix */ 
983-     si  =  0 ;
974+     int   si  =  0 ;
984975    if  (copysign (1.0 , x ) ==  -1.0 ) {
985976        s [si ] =  '-' ;
986977        si ++ ;
@@ -995,18 +986,21 @@ _Py_dg_dtoa_hex(double x, int precision, int always_add_sign,
995986    si ++ ;
996987
997988    /* mantissa */ 
998-     s [si ] =  char_from_hex ((int )m , upper );
989+     const  char  * hexmap  =  upper  ? Py_hexdigits_upper  : Py_hexdigits ;
990+     assert (0  <= (int )m  <  16 );
991+     s [si ] =  hexmap [(int )m ];
999992    si ++ ;
1000993    m  -=  (int )m ;
1001994    s [si ] =  '.' ;
1002-     for  (i = 0 ; i  <  precision ; i ++ ) {
995+     for  (int   i   =   0 ; i  <  precision ; i ++ ) {
1003996        si ++ ;
1004997        m  *= 16.0 ;
1005-         s [si ] =  char_from_hex ((int )m , upper );
998+         assert (0  <= (int )m  <  16 );
999+         s [si ] =  hexmap [(int )m ];
10061000        m  -=  (int )m ;
10071001    }
10081002
1009-     /* clear trailing zeros from mantissa */ 
1003+     /* clear trailing zeros from mantissa (and maybe the dot)  */ 
10101004    while  (s [si ] ==  '0' ) {
10111005        si -- ;
10121006    }
@@ -1017,7 +1011,7 @@ _Py_dg_dtoa_hex(double x, int precision, int always_add_sign,
10171011    /* exponent */ 
10181012    s [si ] =  upper  ? 'P'  : 'p' ;
10191013    si ++ ;
1020-     i  =  snprintf (s + si , DBL_MAX_EXP + 1 , "%+d" , e );
1014+     int   i  =  snprintf (s + si , DBL_MAX_EXP + 1 , "%+d" , e );
10211015    si  +=  i + 1 ;
10221016
10231017    return  PyMem_Realloc (s , si );
0 commit comments