@@ -1115,6 +1115,15 @@ auto write_inf_nan(char* buffer, bool is_nan) noexcept -> char* {
11151115 return memcpy (buffer, is_nan ? " nan" : " inf" , 4 ), buffer + 3 ;
11161116}
11171117
1118+ // Copies at most `end - dst` bytes of `src[0..n)` to `dst`, returning the end
1119+ // of the written range.
1120+ ZMIJ_INLINE auto write_upto (char * dst, char * end, const char * src,
1121+ size_t n) noexcept -> char* {
1122+ size_t take = n < size_t (end - dst) ? n : size_t (end - dst);
1123+ memcpy (dst, src, take);
1124+ return dst + take;
1125+ }
1126+
11181127// Writes zero in fixed notation, e.g. "0.000" (or "0" when precision is 0).
11191128ZMIJ_INLINE auto write_zero (char * buffer, int precision) noexcept -> char* {
11201129 *buffer++ = ' 0' ;
@@ -1662,17 +1671,13 @@ auto write_scientific_big(double value, int precision, char* out,
16621671 char digits[805 ]; // num < 2**2668 has at most 804 digits, plus a carry digit.
16631672 digits[0 ] = ' 0' ;
16641673 char * p = digits;
1665- int num_sig = precision + 1 ; // significant digits requested
1666- int avail = 1 ; // significant digits available to emit (>= 1)
1667- int lead_exp = 0 ; // exponent of the leading digit
1674+ int num_avail_digits = 1 ; // significant digits to emit (>= 1)
1675+ int lead_exp = 0 ; // exponent of the leading digit
16681676
16691677 bool is_normal = unsigned (raw_exp - 1 ) < unsigned (traits::exp_mask - 1 );
16701678 if (!is_normal) [[ZMIJ_UNLIKELY]] {
1671- if (raw_exp != 0 ) { // inf or nan
1672- size_t size = size_t (end - dst) < 3 ? size_t (end - dst) : 3 ;
1673- memcpy (dst, bin_sig != 0 ? " nan" : " inf" , size);
1674- return dst + size;
1675- }
1679+ if (raw_exp != 0 ) // inf or nan
1680+ return write_upto (dst, end, bin_sig != 0 ? " nan" : " inf" , 3 );
16761681 if (bin_sig != 0 ) normalize<double >(bin_sig, raw_exp);
16771682 }
16781683
@@ -1696,23 +1701,24 @@ auto write_scientific_big(double value, int precision, char* out,
16961701 int num_digits = int (digits + sizeof (digits) - p);
16971702 lead_exp = num_digits - 1 + base_exp;
16981703
1699- // Round to num_sig significant digits, ties to even.
1700- if (num_digits > num_sig) {
1701- char dropped = p[num_sig];
1704+ int num_req_digits = precision + 1 ;
1705+ // Round to num_req_digits significant digits, ties to even.
1706+ if (num_digits > num_req_digits) {
1707+ char dropped = p[num_req_digits];
17021708 bool round_up = dropped > ' 5' ;
17031709 // A dropped 5 is a tie unless a lower nonzero digit makes it sticky.
17041710 if (dropped == ' 5' ) {
1705- round_up = (p[num_sig - 1 ] - ' 0' ) & 1 ;
1706- for (char * q = p + num_sig + 1 ; q < p + num_digits; ++q) {
1711+ round_up = (p[num_req_digits - 1 ] - ' 0' ) & 1 ;
1712+ for (char * q = p + num_req_digits + 1 ; q < p + num_digits; ++q) {
17071713 if (*q != ' 0' ) {
17081714 round_up = true ;
17091715 break ;
17101716 }
17111717 }
17121718 }
1713- num_digits = num_sig ;
1719+ num_digits = num_req_digits ;
17141720 if (round_up) {
1715- char * q = p + num_sig - 1 ;
1721+ char * q = p + num_req_digits - 1 ;
17161722 // Propagate the carry over trailing nines.
17171723 while (*q == ' 9' ) *q-- = ' 0' ;
17181724 // 999.. rolling over to 1000.. adds a significant digit.
@@ -1724,26 +1730,22 @@ auto write_scientific_big(double value, int precision, char* out,
17241730 }
17251731 }
17261732 }
1727- avail = num_digits < num_sig ? num_digits : num_sig ;
1733+ num_avail_digits = num_digits;
17281734 }
17291735
17301736 // Emit d.ddd...e±XX with `precision` fractional digits, zero-padded, writing
17311737 // at most `end - dst` characters.
17321738 if (dst < end) *dst++ = p[0 ];
17331739 if (dst < end) *dst++ = ' .' ;
1734- size_t frac = size_t (avail - 1 );
1735- size_t take = frac < size_t (end - dst) ? frac : size_t (end - dst);
1736- memcpy (dst, p + 1 , take);
1737- dst += take;
1738- size_t zeros = size_t (precision) - frac;
1739- take = zeros < size_t (end - dst) ? zeros : size_t (end - dst);
1740- memset (dst, ' 0' , take);
1741- dst += take;
1740+ int num_frac_digits = num_avail_digits - 1 ;
1741+ dst = write_upto (dst, end, p + 1 , size_t (num_frac_digits));
1742+ int num_zeros = precision - num_frac_digits;
1743+ if (num_zeros > end - dst) num_zeros = int (end - dst);
1744+ memset (dst, ' 0' , num_zeros);
1745+ dst += num_zeros;
17421746 char exp[8 ];
1743- size_t exp_len = size_t (write_exp<double >(exp, lead_exp) - exp);
1744- take = exp_len < size_t (end - dst) ? exp_len : size_t (end - dst);
1745- memcpy (dst, exp, take);
1746- return dst + take;
1747+ char * exp_end = write_exp<double >(exp, lead_exp);
1748+ return write_upto (dst, end, exp, size_t (exp_end - exp));
17471749}
17481750
17491751template <typename Float>
0 commit comments