Skip to content

Commit e1d64b7

Browse files
[libc] Enable dyadic float for float printf (#110765)
Dyadic floats were an existing option for float to string conversion, but it had become stale. This patch fixes it up as well as adding proper config options and test support. Due to the test changes this is a followup to #110759
1 parent d617371 commit e1d64b7

File tree

8 files changed

+48
-12
lines changed

8 files changed

+48
-12
lines changed

libc/config/config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@
2222
"value": false,
2323
"doc": "Use large table for better printf long double performance."
2424
},
25+
"LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_DYADIC_FLOAT": {
26+
"value": false,
27+
"doc": "Use dyadic float for faster and smaller but less accurate printf doubles."
28+
},
29+
"LIBC_CONF_PRINTF_FLOAT_TO_STR_NO_SPECIALIZE_LD": {
30+
"value": false,
31+
"doc": "Use the same mode for double and long double in printf."
32+
},
2533
"LIBC_CONF_PRINTF_DISABLE_FIXED_POINT": {
2634
"value": false,
2735
"doc": "Disable printing fixed point values in printf and friends."

libc/docs/configure.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ to learn about the defaults for your platform and target.
4040
- ``LIBC_CONF_PRINTF_DISABLE_INDEX_MODE``: Disable index mode in the printf format string.
4141
- ``LIBC_CONF_PRINTF_DISABLE_STRERROR``: Disable handling of %m to print strerror in printf and friends.
4242
- ``LIBC_CONF_PRINTF_DISABLE_WRITE_INT``: Disable handling of %n in printf format string.
43+
- ``LIBC_CONF_PRINTF_FLOAT_TO_STR_NO_SPECIALIZE_LD``: Use the same mode for double and long double in printf.
44+
- ``LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_DYADIC_FLOAT``: Use dyadic float for faster and smaller but less accurate printf doubles.
4345
- ``LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE``: Use large table for better printf long double performance.
4446
* **"pthread" options**
4547
- ``LIBC_CONF_RAW_MUTEX_DEFAULT_SPIN_COUNT``: Default number of spins before blocking if a mutex is in contention (default to 100).

libc/src/__support/FPUtil/dyadic_float.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ template <size_t Bits> struct DyadicFloat {
357357
return as<T, /*ShouldSignalExceptions=*/false>();
358358
}
359359

360-
LIBC_INLINE explicit constexpr operator MantissaType() const {
360+
LIBC_INLINE constexpr MantissaType as_mantissa_type() const {
361361
if (mantissa.is_zero())
362362
return 0;
363363

libc/src/__support/float_to_string.h

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "src/__support/libc_assert.h"
2121
#include "src/__support/macros/attributes.h"
2222
#include "src/__support/macros/config.h"
23+
#include "src/__support/sign.h"
2324

2425
// This file has 5 compile-time flags to allow the user to configure the float
2526
// to string behavior. These were used to explore tradeoffs during the design
@@ -232,7 +233,7 @@ LIBC_INLINE UInt<MID_INT_SIZE> get_table_positive_df(int exponent, size_t i) {
232233
if (shift_amount < 0) {
233234
return 1;
234235
}
235-
fputil::DyadicFloat<INT_SIZE> num(false, 0, 1);
236+
fputil::DyadicFloat<INT_SIZE> num(Sign::POS, 0, 1);
236237
constexpr UInt<INT_SIZE> MOD_SIZE =
237238
(UInt<INT_SIZE>(EXP10_9)
238239
<< (CALC_SHIFT_CONST + (IDX_SIZE > 1 ? IDX_SIZE : 0)));
@@ -242,16 +243,17 @@ LIBC_INLINE UInt<MID_INT_SIZE> get_table_positive_df(int exponent, size_t i) {
242243
0x89705f4136b4a597}};
243244

244245
static const fputil::DyadicFloat<INT_SIZE> FIVE_EXP_MINUS_NINE(
245-
false, -276, FIVE_EXP_MINUS_NINE_MANT);
246+
Sign::POS, -276, FIVE_EXP_MINUS_NINE_MANT);
246247

247248
if (i > 0) {
248-
fputil::DyadicFloat<INT_SIZE> fives = fputil::pow_n(FIVE_EXP_MINUS_NINE, i);
249+
fputil::DyadicFloat<INT_SIZE> fives =
250+
fputil::pow_n(FIVE_EXP_MINUS_NINE, static_cast<uint32_t>(i));
249251
num = fives;
250252
}
251253
num = mul_pow_2(num, shift_amount);
252254

253255
// Adding one is part of the formula.
254-
UInt<INT_SIZE> int_num = static_cast<UInt<INT_SIZE>>(num) + 1;
256+
UInt<INT_SIZE> int_num = num.as_mantissa_type() + 1;
255257
if (int_num > MOD_SIZE) {
256258
auto rem =
257259
int_num
@@ -339,23 +341,24 @@ LIBC_INLINE UInt<MID_INT_SIZE> get_table_negative_df(int exponent, size_t i) {
339341

340342
int shift_amount = CALC_SHIFT_CONST - exponent;
341343

342-
fputil::DyadicFloat<INT_SIZE> num(false, 0, 1);
344+
fputil::DyadicFloat<INT_SIZE> num(Sign::POS, 0, 1);
343345
constexpr UInt<INT_SIZE> MOD_SIZE =
344346
(UInt<INT_SIZE>(EXP10_9)
345347
<< (CALC_SHIFT_CONST + (IDX_SIZE > 1 ? IDX_SIZE : 0)));
346348

347349
constexpr UInt<INT_SIZE> TEN_EXP_NINE_MANT(EXP10_9);
348350

349-
static const fputil::DyadicFloat<INT_SIZE> TEN_EXP_NINE(false, 0,
351+
static const fputil::DyadicFloat<INT_SIZE> TEN_EXP_NINE(Sign::POS, 0,
350352
TEN_EXP_NINE_MANT);
351353

352354
if (i > 0) {
353-
fputil::DyadicFloat<INT_SIZE> tens = fputil::pow_n(TEN_EXP_NINE, i);
355+
fputil::DyadicFloat<INT_SIZE> tens =
356+
fputil::pow_n(TEN_EXP_NINE, static_cast<uint32_t>(i));
354357
num = tens;
355358
}
356359
num = mul_pow_2(num, shift_amount);
357360

358-
UInt<INT_SIZE> int_num = static_cast<UInt<INT_SIZE>>(num);
361+
UInt<INT_SIZE> int_num = num.as_mantissa_type();
359362
if (int_num > MOD_SIZE) {
360363
auto rem =
361364
int_num

libc/src/stdio/printf_core/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ endif()
1010
if(LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE)
1111
list(APPEND printf_config_copts "-DLIBC_COPT_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE")
1212
endif()
13+
if(LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_DYADIC_FLOAT)
14+
list(APPEND printf_config_copts "-DLIBC_COPT_FLOAT_TO_STR_USE_DYADIC_FLOAT")
15+
endif()
16+
if(LIBC_CONF_PRINTF_FLOAT_TO_STR_NO_SPECIALIZE_LD)
17+
list(APPEND printf_config_copts "-DLIBC_COPT_FLOAT_TO_STR_NO_SPECIALIZE_LD")
18+
endif()
1319
if(LIBC_CONF_PRINTF_DISABLE_FIXED_POINT)
1420
list(APPEND printf_config_copts "-DLIBC_COPT_PRINTF_DISABLE_FIXED_POINT")
1521
endif()

libc/test/src/stdio/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ add_libc_test(
116116
if(LIBC_CONF_PRINTF_DISABLE_FLOAT)
117117
list(APPEND sprintf_test_copts "-DLIBC_COPT_PRINTF_DISABLE_FLOAT")
118118
endif()
119+
if(LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_DYADIC_FLOAT)
120+
list(APPEND sprintf_test_copts "-DLIBC_COPT_FLOAT_TO_STR_REDUCED_PRECISION")
121+
endif()
119122
if(LIBC_CONF_PRINTF_DISABLE_INDEX_MODE)
120123
list(APPEND sprintf_test_copts "-DLIBC_COPT_PRINTF_DISABLE_INDEX_MODE")
121124
endif()

libc/test/src/stdlib/CMakeLists.txt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,13 +168,17 @@ add_libc_test(
168168
.strtol_test_support
169169
)
170170

171+
if(LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_DYADIC_FLOAT)
172+
list(APPEND strfrom_test_copts "-DLIBC_COPT_FLOAT_TO_STR_REDUCED_PRECISION")
173+
endif()
174+
171175
add_header_library(
172176
strfrom_test_support
173177
HDRS
174-
StrfromTest.h
178+
StrfromTest.h
175179
DEPENDS
176-
libc.src.__support.CPP.type_traits
177-
libc.src.__support.FPUtil.fp_bits
180+
libc.src.__support.CPP.type_traits
181+
libc.src.__support.FPUtil.fp_bits
178182
)
179183

180184
add_libc_test(
@@ -186,6 +190,8 @@ add_libc_test(
186190
DEPENDS
187191
.strfrom_test_support
188192
libc.src.stdlib.strfromf
193+
COMPILE_OPTIONS
194+
${strfrom_test_copts}
189195
)
190196

191197
add_libc_test(
@@ -197,6 +203,8 @@ add_libc_test(
197203
DEPENDS
198204
.strfrom_test_support
199205
libc.src.stdlib.strfromd
206+
COMPILE_OPTIONS
207+
${strfrom_test_copts}
200208
)
201209

202210
add_libc_test(
@@ -208,6 +216,8 @@ add_libc_test(
208216
DEPENDS
209217
.strfrom_test_support
210218
libc.src.stdlib.strfroml
219+
COMPILE_OPTIONS
220+
${strfrom_test_copts}
211221
)
212222

213223
add_libc_test(

libc/test/src/stdlib/StrfromTest.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ class StrfromTest : public LIBC_NAMESPACE::testing::Test {
156156
written = func(buff, 99, "%f", 1.5);
157157
ASSERT_STREQ_LEN(written, buff, "1.500000");
158158

159+
// Dyadic float is only accurate to ~50 digits, so skip this 300 digit test.
160+
// TODO: Create way to test just the first ~50 digits of a number.
161+
#ifndef LIBC_COPT_FLOAT_TO_STR_REDUCED_PRECISION
159162
written = func(buff, 499, "%f", 1e300);
160163
ASSERT_STREQ_LEN(written, buff,
161164
"100000000000000005250476025520442024870446858110815915491"
@@ -167,6 +170,7 @@ class StrfromTest : public LIBC_NAMESPACE::testing::Test {
167170
"111903896764088007465274278014249457925878882005684283811"
168171
"566947219638686"
169172
"5459400540160.000000");
173+
#endif // DLIBC_COPT_FLOAT_TO_STR_REDUCED_PRECISION
170174

171175
written = func(buff, 99, "%f", 0.1);
172176
ASSERT_STREQ_LEN(written, buff, "0.100000");

0 commit comments

Comments
 (0)