[libc-commits] [libc] [libc] Fix printf long double truncation bound (PR #70705)
via libc-commits
libc-commits at lists.llvm.org
Mon Oct 30 11:50:42 PDT 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libc
Author: None (michaelrj-google)
<details>
<summary>Changes</summary>
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.
---
Full diff: https://github.com/llvm/llvm-project/pull/70705.diff
2 Files Affected:
- (modified) libc/src/stdio/printf_core/float_dec_converter.h (+7-5)
- (modified) libc/test/src/stdio/sprintf_test.cpp (+3)
``````````diff
diff --git a/libc/src/stdio/printf_core/float_dec_converter.h b/libc/src/stdio/printf_core/float_dec_converter.h
index 8c5ba0d241eda54..0e152a26025642d 100644
--- a/libc/src/stdio/printf_core/float_dec_converter.h
+++ b/libc/src/stdio/printf_core/float_dec_converter.h
@@ -85,11 +85,13 @@ LIBC_INLINE RoundDirection get_round_direction(int last_digit, bool truncated,
template <typename T>
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_integral_v<T>, bool>
-zero_after_digits(int32_t base_2_exp, int32_t digits_after_point, T mantissa) {
+zero_after_digits(int32_t base_2_exp, int32_t digits_after_point, T mantissa,
+ const int32_t mant_width) {
const int32_t required_twos = -base_2_exp - digits_after_point - 1;
+ // Add 8 to mant width since this is a loose bound.
const bool has_trailing_zeros =
required_twos <= 0 ||
- (required_twos < 60 &&
+ (required_twos < (mant_width + 8) &&
multiple_of_power_of_2(mantissa, static_cast<uint32_t>(required_twos)));
return has_trailing_zeros;
}
@@ -568,7 +570,7 @@ LIBC_INLINE int convert_float_decimal_typed(Writer *writer,
RoundDirection round;
const bool truncated =
!zero_after_digits(exponent - MANT_WIDTH, precision,
- float_bits.get_explicit_mantissa());
+ float_bits.get_explicit_mantissa(), MANT_WIDTH);
round = get_round_direction(last_digit, truncated, is_negative);
RET_IF_RESULT_NEGATIVE(
@@ -733,7 +735,7 @@ LIBC_INLINE int convert_float_dec_exp_typed(Writer *writer,
// Use the formula from %f.
truncated =
!zero_after_digits(exponent - MANT_WIDTH, precision - final_exponent,
- float_bits.get_explicit_mantissa());
+ float_bits.get_explicit_mantissa(), MANT_WIDTH);
}
}
round = get_round_direction(last_digit, truncated, is_negative);
@@ -979,7 +981,7 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer *writer,
// Use the formula from %f.
truncated =
!zero_after_digits(exponent - MANT_WIDTH, exp_precision - base_10_exp,
- float_bits.get_explicit_mantissa());
+ float_bits.get_explicit_mantissa(), MANT_WIDTH);
}
}
diff --git a/libc/test/src/stdio/sprintf_test.cpp b/libc/test/src/stdio/sprintf_test.cpp
index b2c321c0b15c9dc..a8fe8f2557c8ef9 100644
--- a/libc/test/src/stdio/sprintf_test.cpp
+++ b/libc/test/src/stdio/sprintf_test.cpp
@@ -1041,6 +1041,9 @@ TEST_F(LlvmLibcSPrintfTest, FloatDecimalConv) {
written = LIBC_NAMESPACE::sprintf(buff, "%Lf", 1.0L);
ASSERT_STREQ_LEN(written, buff, "1.000000");
+ written = LIBC_NAMESPACE::sprintf(buff, "%.Lf", -2.5L);
+ ASSERT_STREQ_LEN(written, buff, "-2");
+
#if defined(SPECIAL_X86_LONG_DOUBLE)
written = LIBC_NAMESPACE::sprintf(buff, "%Lf", 1e100L);
``````````
</details>
https://github.com/llvm/llvm-project/pull/70705
More information about the libc-commits
mailing list