Skip to content

Commit 63f8922

Browse files
[libc] Fix printf g conversion with high precision
The number of trailing zeroes was being calculated incorrectly. It was assuming that it could add all of the implicit leading zeroes in the final block, not accounting for the number of digits actually reqested by the precision. Reviewed By: lntue Differential Revision: https://reviews.llvm.org/D156489
1 parent ca74ad8 commit 63f8922

File tree

2 files changed

+35
-9
lines changed

2 files changed

+35
-9
lines changed

libc/src/stdio/printf_core/float_dec_converter.h

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -965,15 +965,6 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer *writer,
965965
if (digits_checked == 0) {
966966
last_block_size = int_to_str.size();
967967
implicit_leading_zeroes = 0;
968-
} else {
969-
// If the block is not the maximum size, that means it has leading
970-
// zeroes, and zeroes are not nines.
971-
if (implicit_leading_zeroes > 0) {
972-
trailing_nines = 0;
973-
}
974-
975-
// But leading zeroes are zeroes (that could be trailing).
976-
trailing_zeroes += implicit_leading_zeroes;
977968
}
978969

979970
int digits_requested = (exp_precision + 1) - digits_checked;
@@ -983,6 +974,19 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer *writer,
983974
digits_to_check = 0;
984975
}
985976

977+
// If the block is not the maximum size, that means it has leading
978+
// zeroes, and zeroes are not nines.
979+
if (implicit_leading_zeroes > 0) {
980+
trailing_nines = 0;
981+
}
982+
983+
// But leading zeroes are zeroes (that could be trailing). We take the
984+
// minimum of the leading zeroes and digits requested because if there are
985+
// more requested digits than leading zeroes we shouldn't count those.
986+
trailing_zeroes +=
987+
(implicit_leading_zeroes > digits_requested ? digits_requested
988+
: implicit_leading_zeroes);
989+
986990
// Check the upper digits of this block.
987991
for (int i = 0; i < digits_to_check; ++i) {
988992
if (int_to_str[i] == '9') {
@@ -1103,6 +1107,24 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer *writer,
11031107
} else {
11041108
// If alt form isn't set, then we need to determine the number of trailing
11051109
// zeroes and set the precision such that they are removed.
1110+
1111+
/*
1112+
Here's a diagram of an example:
1113+
1114+
printf("%.15g", 22.25);
1115+
1116+
+--- init_precision = 15
1117+
|
1118+
+-------------------+
1119+
| |
1120+
| ++--- trimmed_precision = 2
1121+
| || |
1122+
22.250000000000000000
1123+
|| | |
1124+
++ +--------------+
1125+
| |
1126+
base_10_exp + 1 = 2 --+ +--- trailing_zeroes = 11
1127+
*/
11061128
int trimmed_precision =
11071129
digits_checked - (base_10_exp + 1) - trailing_zeroes;
11081130
if (trimmed_precision < 0) {

libc/test/src/stdio/sprintf_test.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2437,6 +2437,10 @@ TEST_F(LlvmLibcSPrintfTest, FloatAutoConv) {
24372437
written = __llvm_libc::sprintf(buff, "%.3g", 1256.0);
24382438
ASSERT_STREQ_LEN(written, buff, "1.26e+03");
24392439

2440+
// Found through large scale testing.
2441+
written = __llvm_libc::sprintf(buff, "%.15g", 22.25);
2442+
ASSERT_STREQ_LEN(written, buff, "22.25");
2443+
24402444
// Subnormal Precision Tests
24412445

24422446
written = __llvm_libc::sprintf(buff, "%.310g", 0x1.0p-1022);

0 commit comments

Comments
 (0)