to_chars or not to_chars?

I was recently adding my Schubfach double-to-string conversion algorithm implementation to dtoa-benchmark and noticed that std::to_chars was notably missing from that benchmark. So I decided to add it and see how well it compares to other methods.

And it did pretty well! This particular implementation from libc++ was 17 times faster than sprintf and almost 2 times faster than double-conversion. Considering that std::to_chars has been available since 2017, I think it’s time to retire double-conversion.

There is still a considerable gap to other state-of-the-art libraries like Schubfach and Dragonbox (used in {fmt}), but performance should be more than sufficient for most use cases.

You can also clearly see that libc++ uses Ryu because their performance profiles are nearly identical, with stock implementation being just a bit faster.

The binary code is surprisingly reasonable too. For example

#include <charconv>

int main() {
  char buf[25];
  *std::to_chars(buf, buf + 25, 4.2).ptr = 0;
}

generates

main:
        sub     rsp, 40
        movsd   xmm0, QWORD PTR .LC0[rip]
        mov     rdi, rsp
        lea     rsi, [rsp+25]
        call    std::to_chars(char*, char*, double)
        mov     BYTE PTR [rax], 0
        xor     eax, eax
        add     rsp, 40
        ret
.LC0:
        .long   -858993459
        .long   1074842828

Godbolt: https://www.godbolt.org/z/jvahnosed

Hopefully it will remain like this, and the C++ committee resists the urge of adding wide char, locale, range and other irrelevant functionality to this low-level API.

P.S. I was surprised to see that my toy 150-line double-to-string conversion algorithm was 15% faster than sprintf.


Last modified on 2025-12-05