Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use std::to_chars instead of std::snprintf for converting numbers to string #18

Closed
cschreib opened this issue Nov 3, 2022 · 2 comments
Labels
enhancement New feature or request
Milestone

Comments

@cschreib
Copy link
Member

cschreib commented Nov 3, 2022

std::snprintf insists on adding a null-terminating character all the time, which forces us to loose one character when running out of space. This is normally not a problem, because we will usually truncate with ... anyway (hence overwriting the last three characters), but just out of principle.

std::to_chars is the modern alternative. I haven't seen benchmarks to compare the performance, but I would expect it to be faster (edit: it is massively faster). The downside of std::to_chars is that it won't write anything if there's not enough space, so we need to handle that logic ourselves. The other big downside is that std::to_chars for floating point numbers has poor vendor support, and was added only in libstdc++ 11, libc++ 14 despite being a C++17 feature (MSVC did better there).

Work in progress on this is started in https://github.com/cschreib/snatch/tree/to_chars.

@cschreib cschreib added the enhancement New feature or request label Nov 3, 2022
@cschreib cschreib added this to the v1.x milestone Nov 28, 2022
@cschreib cschreib modified the milestones: v1.1, v1.x Mar 28, 2023
@cschreib
Copy link
Member Author

cschreib commented May 1, 2023

As an alternative, we now have our own constexpr-friendly code to do number-to-string conversions. On clang++-17 with libc++-17, I get the following relative performance (lower is better):

Debug Release
std::snprintf 1 1
std::to_chars 0.14 0.085
snitch::append_constexpr 2.8 0.39

In Debug the comparison isn't very fair, since snitch::append_constexpr is fully un-optimised, while the other two are taken pre-compiled from an optimised build of libc++. But although unfair, that's the reality of how it would be used in practice. This shows that our implementation is 3x slower than std::snprintf, and 20x slower than std::to_chars.

In Release the comparison is fair. We're now 3x faster than std::snprintf, but still 5x slower than std::to_chars.

So the tradeoff of using snitch::append_constexpr instead of std::snprintf would be worse perf in Debug, and better perf in Release. Clearly, std::to_chars would be the best though (sadly not constexpr for floating point numbers yet).

Using the following for std::to_chars:

template<typename T>
bool append_to_chars(snitch::small_string_span ss, T value) noexcept {
    auto [end, err] = std::to_chars(
        ss.end(), ss.begin() + ss.capacity(), value, std::chars_format::scientific, 6);
    if (err != std::errc{}) {
        snitch::small_string<32> fallback;
        auto [end2, err2] = std::to_chars(
            fallback.end(), fallback.begin() + fallback.capacity(), value,
            std::chars_format::scientific, 6);
        if (err2 != std::errc{}) {
            return false;
        }

        fallback.grow(end2 - fallback.end());
        return append(ss, fallback);
    }

    ss.grow(end - ss.end());
    return true;
}

@cschreib
Copy link
Member Author

cschreib commented May 2, 2024

Completed in #160.

@cschreib cschreib closed this as completed May 2, 2024
@cschreib cschreib modified the milestones: v1.x, v1.2.5 May 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant