Skip to content

Commit 8ca565c

Browse files
[libc] Fix printf long double truncation bound (#70705)
The calculation for if a number being printed is truncated and should be rounded up assumed a double for one of its constants, causing occassional misrounding. This fixes that by making the constant based on the mantissa width.
1 parent 55c9f24 commit 8ca565c

File tree

2 files changed

+10
-5
lines changed

2 files changed

+10
-5
lines changed

libc/src/stdio/printf_core/float_dec_converter.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,13 @@ LIBC_INLINE RoundDirection get_round_direction(int last_digit, bool truncated,
8585

8686
template <typename T>
8787
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_integral_v<T>, bool>
88-
zero_after_digits(int32_t base_2_exp, int32_t digits_after_point, T mantissa) {
88+
zero_after_digits(int32_t base_2_exp, int32_t digits_after_point, T mantissa,
89+
const int32_t mant_width) {
8990
const int32_t required_twos = -base_2_exp - digits_after_point - 1;
91+
// Add 8 to mant width since this is a loose bound.
9092
const bool has_trailing_zeros =
9193
required_twos <= 0 ||
92-
(required_twos < 60 &&
94+
(required_twos < (mant_width + 8) &&
9395
multiple_of_power_of_2(mantissa, static_cast<uint32_t>(required_twos)));
9496
return has_trailing_zeros;
9597
}
@@ -568,7 +570,7 @@ LIBC_INLINE int convert_float_decimal_typed(Writer *writer,
568570
RoundDirection round;
569571
const bool truncated =
570572
!zero_after_digits(exponent - MANT_WIDTH, precision,
571-
float_bits.get_explicit_mantissa());
573+
float_bits.get_explicit_mantissa(), MANT_WIDTH);
572574
round = get_round_direction(last_digit, truncated, is_negative);
573575

574576
RET_IF_RESULT_NEGATIVE(
@@ -733,7 +735,7 @@ LIBC_INLINE int convert_float_dec_exp_typed(Writer *writer,
733735
// Use the formula from %f.
734736
truncated =
735737
!zero_after_digits(exponent - MANT_WIDTH, precision - final_exponent,
736-
float_bits.get_explicit_mantissa());
738+
float_bits.get_explicit_mantissa(), MANT_WIDTH);
737739
}
738740
}
739741
round = get_round_direction(last_digit, truncated, is_negative);
@@ -979,7 +981,7 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer *writer,
979981
// Use the formula from %f.
980982
truncated =
981983
!zero_after_digits(exponent - MANT_WIDTH, exp_precision - base_10_exp,
982-
float_bits.get_explicit_mantissa());
984+
float_bits.get_explicit_mantissa(), MANT_WIDTH);
983985
}
984986
}
985987

libc/test/src/stdio/sprintf_test.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,6 +1041,9 @@ TEST_F(LlvmLibcSPrintfTest, FloatDecimalConv) {
10411041
written = LIBC_NAMESPACE::sprintf(buff, "%Lf", 1.0L);
10421042
ASSERT_STREQ_LEN(written, buff, "1.000000");
10431043

1044+
written = LIBC_NAMESPACE::sprintf(buff, "%.Lf", -2.5L);
1045+
ASSERT_STREQ_LEN(written, buff, "-2");
1046+
10441047
#if defined(SPECIAL_X86_LONG_DOUBLE)
10451048

10461049
written = LIBC_NAMESPACE::sprintf(buff, "%Lf", 1e100L);

0 commit comments

Comments
 (0)