Repository navigation
Conversation
Collaborator
|
It could be an interesting idea to offer a |
Member
Author
|
@LeszekSwirski I like it, let us see whether this could be beneficial. |
Member
Author
|
@LeszekSwirski I have opened it as an issue for research. |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Users can now tell fast_float what to expect from their data or their program, so that it parses faster. The hints are a template argument; nothing else changes:
Without hints, the code is that of
main: existing calls compile and run as before.The hints
unpredictable_sign: the sign is handled without a branch, in the parser and in Clinger's fast path (which then multiplies or divides by a signed power of ten). This helps when positive and negative numbers come in random order (e.g., gains and losses), and costs when the signs are predictable.assume_round_to_nearest: fast_float does not check the rounding mode before Clinger's fast path. It replaces theFASTFLOAT_ROUNDS_TO_NEARESTmacro (added after v8.3.3 and never released), which is removed. Unlike the macro, it applies call by call and cannot cause ODR violations.short_numbers: when the range[first, last)holds a single number of at most 8 characters without an exponent (e.g.,-12.5), it is parsed with a few bitwise operations (SWAR) in the caller, with no branch on its shape. This helps when the shapes vary unpredictably and costs when they are predictable. Only forcharinputs andfloat/double.The hints are a separate type (
fast_float::performance_hints) rather thanchars_formatflags, so they cannot be passed at run time by mistake. The JSON and JavaScript formats ignoreunpredictable_signandshort_numbers.Implementation notes
if constexprin C++17): given an ordinaryif, GCC turns the branch-free sign skip back into a branch on the sign. The sign is detected arithmetically,((c ^ '-') - 1) >> 63, for the same reason.chars_format::generaland kept out of line, asmaindoes for the default parser. With GCC, the format is passed as a constant argument so that GCC inlines the parser as it does by default (forcing the inlining made it slower).integer_times_pow10: Clinger's fast path is inlined and the rest is out of line.Benchmarks
realbenchmarkgains a data set of 100,000 prices with random signs and two decimals, andfastfloat (64, unpredictable sign)lines. The hinted loops are inbenchmarks/benchmark_hints.cpp, which replacesbenchmark_rtn.cpp: in the same file, the extra instantiations exhaust GCC's inlining budget and slow down the default loops.Intel Xeon Gold 6338,
fastfloat (64), MB/s, ASCII / UTF-16 (best of two runs):unpredictable_signunpredictable_sign(
mainhas no prices data set; the PR's default line runs the same code.)assume_round_to_nearestperforms as the macro did (within 2–4%).On short numbers with varying shapes (500,000 numbers such as
7,-12.5,1042),short_numberstakes the time per number from 16.1 to 10.8 ns (GCC 15) and from 18.2 to 11.0 ns (Clang 21) on the same Xeon, and from 7.5 to 3.2 ns on an Apple M4 (with all three hints). On short numbers with predictable shapes, it is slower: hence a hint.Tests
tests/performance_hints_test.cppchecks that every combination of hints gives the same value, error and end pointer as no hint, for many formats,char/char16_t/char32_t,float/double,from_chars_advancedwith a comma as decimal point, andinteger_times_pow10with every integer type; thatassume_round_to_nearestagrees withstrtod; and that the existing overloads (explicit types, function pointers, integers) still resolve. It replacesrounds_to_nearest_test.cpp. Also checked: GCC C++11/C++20 (constexpr tests)/C++23 and Clang C++17, without warnings, and fuzzing againstmain.Documentation
The README gains a "Performance hints" section (which absorbs "Assuming the default rounding mode") and an example, "Parsing formatted numbers in one pass", that parses
$1,234.56or-12.5%withinteger_times_pow10(tests/example_formatted.cpp).