@@ -485,6 +485,50 @@ PyOS_ascii_formatd(char *buffer,
485
485
486
486
/* The fallback code to use if _Py_dg_dtoa is not available. */
487
487
488
+ /* Remove trailing zeros after the decimal point from a numeric string; also
489
+ remove the decimal point if all digits following it are zero. The numeric
490
+ string must end in '\0', and should not have any leading or trailing
491
+ whitespace. Assumes that the decimal point is '.'. */
492
+ Py_LOCAL_INLINE (void )
493
+ remove_trailing_zeros (char * buffer )
494
+ {
495
+ char * old_fraction_end , * new_fraction_end , * end , * p ;
496
+
497
+ p = buffer ;
498
+ if (* p == '-' || * p == '+' )
499
+ /* Skip leading sign, if present */
500
+ ++ p ;
501
+ while (isdigit (Py_CHARMASK (* p )))
502
+ ++ p ;
503
+
504
+ /* if there's no decimal point there's nothing to do */
505
+ if (* p ++ != '.' )
506
+ return ;
507
+
508
+ /* scan any digits after the point */
509
+ while (isdigit (Py_CHARMASK (* p )))
510
+ ++ p ;
511
+ old_fraction_end = p ;
512
+
513
+ /* scan up to ending '\0' */
514
+ while (* p != '\0' )
515
+ p ++ ;
516
+ /* +1 to make sure that we move the null byte as well */
517
+ end = p + 1 ;
518
+
519
+ /* scan back from fraction_end, looking for removable zeros */
520
+ p = old_fraction_end ;
521
+ while (* (p - 1 ) == '0' )
522
+ -- p ;
523
+ /* and remove point if we've got that far */
524
+ if (* (p - 1 ) == '.' )
525
+ -- p ;
526
+ new_fraction_end = p ;
527
+
528
+ memmove (new_fraction_end , old_fraction_end , end - old_fraction_end );
529
+ }
530
+
531
+
488
532
PyAPI_FUNC (char * ) PyOS_double_to_string (double val ,
489
533
char format_code ,
490
534
int precision ,
@@ -498,6 +542,7 @@ PyAPI_FUNC(char *) PyOS_double_to_string(double val,
498
542
char * p ;
499
543
int t ;
500
544
int upper = 0 ;
545
+ int strip_trailing_zeros = 0 ;
501
546
502
547
/* Validate format_code, and map upper and lower case */
503
548
switch (format_code ) {
@@ -532,8 +577,17 @@ PyAPI_FUNC(char *) PyOS_double_to_string(double val,
532
577
PyErr_BadInternalCall ();
533
578
return NULL ;
534
579
}
535
- precision = 12 ;
536
- format_code = 'g' ;
580
+ /* switch to exponential notation at 1e11, or 1e12 if we're
581
+ not adding a .0 */
582
+ if (fabs (val ) >= (flags & Py_DTSF_ADD_DOT_0 ? 1e11 : 1e12 )) {
583
+ precision = 11 ;
584
+ format_code = 'e' ;
585
+ strip_trailing_zeros = 1 ;
586
+ }
587
+ else {
588
+ precision = 12 ;
589
+ format_code = 'g' ;
590
+ }
537
591
break ;
538
592
default :
539
593
PyErr_BadInternalCall ();
@@ -554,11 +608,14 @@ PyAPI_FUNC(char *) PyOS_double_to_string(double val,
554
608
t = Py_DTST_FINITE ;
555
609
556
610
557
- if (flags & Py_DTSF_ADD_DOT_0 )
611
+ if (( flags & Py_DTSF_ADD_DOT_0 ) && ( format_code != 'e' ) )
558
612
format_code = 'Z' ;
559
613
560
614
PyOS_snprintf (format , 32 , "%%%s.%i%c" , (flags & Py_DTSF_ALT ? "#" : "" ), precision , format_code );
561
615
PyOS_ascii_formatd (buf , sizeof (buf ), format , val );
616
+ /* remove trailing zeros if necessary */
617
+ if (strip_trailing_zeros )
618
+ remove_trailing_zeros (buf );
562
619
}
563
620
564
621
len = strlen (buf );
@@ -671,7 +728,7 @@ format_float_short(double d, char format_code,
671
728
assert (digits_end != NULL && digits_end >= digits );
672
729
digits_len = digits_end - digits ;
673
730
674
- if (digits_len && !isdigit (digits [0 ])) {
731
+ if (digits_len && !isdigit (Py_CHARMASK ( digits [0 ]) )) {
675
732
/* Infinities and nans here; adapt Gay's output,
676
733
so convert Infinity to inf and NaN to nan, and
677
734
ignore sign of nan. Then return. */
0 commit comments