diff --git a/libc/src/stdio/printf_core/float_dec_converter.h b/libc/src/stdio/printf_core/float_dec_converter.h --- a/libc/src/stdio/printf_core/float_dec_converter.h +++ b/libc/src/stdio/printf_core/float_dec_converter.h @@ -493,6 +493,10 @@ } }; +// This implementation is based on the Ryu Printf algorithm by Ulf Adams: +// Ulf Adams. 2019. Ryƫ revisited: printf floating point conversion. +// Proc. ACM Program. Lang. 3, OOPSLA, Article 169 (October 2019), 23 pages. +// https://doi.org/10.1145/3360595 template , int> = 0> LIBC_INLINE int convert_float_decimal_typed(Writer *writer, const FormatSection &to_conv, @@ -590,7 +594,7 @@ RoundDirection round; // Is m * 10^(additionalDigits + 1) / 2^(-exponent) integer? const int32_t requiredTwos = - -exponent - MANT_WIDTH - static_cast(precision) - 1; + -(exponent - MANT_WIDTH) - static_cast(precision) - 1; const bool trailingZeros = requiredTwos <= 0 || (requiredTwos < 60 && @@ -764,7 +768,7 @@ RoundDirection round; // Is m * 10^(additionalDigits + 1) / 2^(-exponent) integer? const int32_t requiredTwos = - -exponent - MANT_WIDTH - static_cast(precision) - 1; + -(exponent - MANT_WIDTH) - static_cast(precision) - 1; const bool trailingZeros = requiredTwos <= 0 || (requiredTwos < 60 && @@ -1011,7 +1015,7 @@ RoundDirection round; // Is m * 10^(additionalDigits + 1) / 2^(-exponent) integer? const int32_t requiredTwos = - -exponent - MANT_WIDTH - static_cast(exp_precision) - 1; + -(exponent - MANT_WIDTH) - static_cast(exp_precision) - 1; // TODO: rename this variable to remove confusion with trailing_zeroes const bool trailingZeros = requiredTwos <= 0 || diff --git a/libc/test/src/stdio/sprintf_test.cpp b/libc/test/src/stdio/sprintf_test.cpp --- a/libc/test/src/stdio/sprintf_test.cpp +++ b/libc/test/src/stdio/sprintf_test.cpp @@ -1140,6 +1140,13 @@ written = __llvm_libc::sprintf(buff, "%.5f", 1.008e3); ASSERT_STREQ_LEN(written, buff, "1008.00000"); + // Found with the help of Fred Tydeman's tbin2dec test. + written = __llvm_libc::sprintf(buff, "%.1f", 0x1.1000000000006p+3); + ASSERT_STREQ_LEN(written, buff, "8.5"); + + written = __llvm_libc::sprintf(buff, "%.0f", 0x1.1000000000006p+3); + ASSERT_STREQ_LEN(written, buff, "9"); + // Subnormal Precision Tests written = __llvm_libc::sprintf(buff, "%.310f", 0x1.0p-1022);