@@ -501,28 +501,24 @@ inline auto read8(char* buffer) noexcept -> uint64_t {
501501 return r;
502502}
503503
504- // Writes a significand consisting of up to 9 decimal digits (7-9 for normals)
505- // and removes trailing zeros.
506- auto write_significand9 (char * buffer, uint32_t value, bool has9digits) noexcept
507- -> char* {
508- buffer = write_if (buffer, value / 100'000'000 , has9digits);
509- uint64_t bcd = to_bcd8 (value % 100'000'000 );
510- write8 (buffer, bcd + zeros);
511- return buffer + count_trailing_nonzeros (bcd);
512- }
513-
514- // Writes a significand consisting of up to 17 decimal digits (16-17 for
515- // normals) and removes trailing zeros. The significant digits start
516- // from buffer[1]. buffer[0] may contain '0' after this function if
517- // the significand has length 16.
518- template <bool use_sse = ZMIJ_USE_SSE != 0 >
519- auto write_significand17 (char * buffer, uint64_t value, bool has17digits,
520- long long value_div10) noexcept -> char* {
504+ // Writes a significand and removes trailing zeros. value has up to 17 decimal
505+ // digits (16-17 for normals) for double (num_bits == 64) and up to 9 digits
506+ // (8-9 for normals) for float. The significant digits start from buffer[1].
507+ // buffer[0] may contain '0' after this function if the leading digit is zero.
508+ template <int num_bits, bool use_sse = ZMIJ_USE_SSE != 0 && num_bits == 64 >
509+ auto write_significand (char * buffer, uint64_t value, bool extra_digit,
510+ long long value_div10) noexcept -> char* {
511+ if (num_bits == 32 ) {
512+ buffer = write_if (buffer, value / 100'000'000 , extra_digit);
513+ uint64_t bcd = to_bcd8 (value % 100'000'000 );
514+ write8 (buffer, bcd + zeros);
515+ return buffer + count_trailing_nonzeros (bcd);
516+ }
521517 if (!ZMIJ_USE_NEON && !use_sse) {
522518 // Digits/pairs of digits are denoted by letters: value = abbccddeeffgghhii.
523519 uint32_t abbccddee = uint32_t (value / 100'000'000 );
524520 uint32_t ffgghhii = uint32_t (value % 100'000'000 );
525- buffer = write_if (buffer, abbccddee / 100'000'000 , has17digits );
521+ buffer = write_if (buffer, abbccddee / 100'000'000 , extra_digit );
526522 uint64_t bcd = to_bcd8 (abbccddee % 100'000'000 );
527523 write8 (buffer, bcd + zeros);
528524 if (ffgghhii == 0 ) {
@@ -565,7 +561,7 @@ auto write_significand17(char* buffer, uint64_t value, bool has17digits,
565561 uint64_t a = uint64_t (umul128 (abbccddee, c->mul_const ) >> 90 );
566562 uint64_t bbccddee = abbccddee - a * hundred_million;
567563
568- buffer = write_if (buffer, a, has17digits );
564+ buffer = write_if (buffer, a, extra_digit );
569565
570566 uint64x1_t ffgghhii_bbccddee_64 = {(uint64_t (ffgghhii) << 32 ) | bbccddee};
571567 int32x2_t bbccddee_ffgghhii = vreinterpret_s32_u64 (ffgghhii_bbccddee_64);
@@ -608,7 +604,7 @@ auto write_significand17(char* buffer, uint64_t value, bool has17digits,
608604 // We always write 17 digits into the buffer, but the first one can be zero.
609605 // buffer points to the second place in the output buffer to allow for the
610606 // insertion of the decimal point, so we can use the first place as scratch.
611- buffer += has17digits - 1 ;
607+ buffer += extra_digit - 1 ;
612608 buffer[16 ] = char (last_digit + ' 0' );
613609
614610 uint32_t abcdefgh = value_div10 / uint64_t (1e8 );
@@ -881,11 +877,9 @@ auto write_fixed(char* buffer, uint64_t dec_sig, int dec_exp, bool extra_digit,
881877 long long dec_sig_div10) noexcept -> char* {
882878 if (dec_exp < 0 ) {
883879 char * point = buffer + 1 ;
884- memcpy (buffer, " 0.0000000" , 8 );
885- buffer = num_bits == 64 ? write_significand17 (buffer + 1 - dec_exp, dec_sig,
886- extra_digit, dec_sig_div10)
887- : write_significand9 (buffer + 1 - dec_exp, dec_sig,
888- extra_digit);
880+ memcpy (buffer, " 0.000000" , 8 );
881+ buffer = write_significand<num_bits>(buffer + 1 - dec_exp, dec_sig,
882+ extra_digit, dec_sig_div10);
889883 if (ZMIJ_USE_SSE) *point = ' .' ;
890884 *buffer = ' \0 ' ;
891885 return buffer;
@@ -895,9 +889,8 @@ auto write_fixed(char* buffer, uint64_t dec_sig, int dec_exp, bool extra_digit,
895889 write8 (buffer + (num_bits == 64 ? 16 : 7 ), 0 );
896890
897891 char * start = buffer;
898- buffer = num_bits == 64 ? write_significand17<false >(buffer, dec_sig, extra_digit,
899- dec_sig_div10)
900- : write_significand9 (buffer, dec_sig, extra_digit);
892+ buffer = write_significand<num_bits, false >(buffer, dec_sig, extra_digit,
893+ dec_sig_div10);
901894
902895 // Branchless move to make space for the '.' without OOB accesses.
903896 char * part1 = start + dec_exp + (dec_exp < 2 );
@@ -989,12 +982,8 @@ auto write(Float value, char* buffer) noexcept -> char* {
989982 dec.sig_div10 );
990983 }
991984 char * start = buffer;
992- if (traits::num_bits == 64 ) {
993- buffer =
994- write_significand17 (buffer + 1 , dec.sig , extra_digit, dec.sig_div10 );
995- } else {
996- buffer = write_significand9 (buffer + 1 , dec.sig , extra_digit);
997- }
985+ buffer = write_significand<traits::num_bits>(buffer + 1 , dec.sig , extra_digit,
986+ dec.sig_div10 );
998987 start[0 ] = start[1 ];
999988 start[1 ] = ' .' ;
1000989 buffer -= (buffer - 1 == start + 1 ); // Remove trailing point.
0 commit comments