Skip to content

fmtlib/dtoa-benchmark

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dtoa benchmark

This project is a complete rewrite of Milo Yip’s dtoa-benchmark, featuring an updated set of algorithms that reflect the current state of the art and a simplified workflow.

Introduction

This benchmark evaluates the performance of converting double-precision IEEE-754 floating-point values (double) to ASCII strings. The function signature is:

void dtoa(double value, char* buffer);

The resulting string must be round-trip convertible: it should parse back to the original value exactly via a correct implementation of strtod.

Note: dtoa is not a standard C or C++ function.

Procedure

The benchmark consists of two phases:

  1. Correctness verification
    All implementations are first validated to ensure round-trip correctness.

  2. Performance measurement

    The benchmark case is:

    • RandomDigit
      • Generate 100,000 random double values (excluding ±inf and NaN).
      • Reduce precision to 1–17 decimal digits in the significand.
      • Convert each value to an ASCII string.

    Each digit group is executed 10 times.
    For each configuration, 10 trials are run and the minimum elapsed time is recorded.

Build and Run

cmake .
make run-benchmark

Results are written in CSV format to:

results/<cpu>_<os>_<compiler>_<commit>.csv

They are also automatically converted to HTML with the same base name.

Results

The following results were measured on a MacBook Pro (Apple M1 Pro) using:

  • Compiler: Apple clang 17.0.0 (clang-1700.0.13.5)
  • OS: macOS
Function Time (ns) Speedup
ostringstream 874.884 1.00×
sprintf 743.801 1.18×
double-conversion 83.519 10.48×
to_chars 43.672 20.03×
ryu 36.865 23.73×
schubfach 24.879 35.16×
fmt 22.338 39.17×
dragonbox 20.641 42.39×
yy 14.335 61.03×
xjb64 10.724 81.58×
zmij 10.087 86.73×
null 0.930 940.73×

Conversion time (smaller is better):

image

ostringstream and sprintf are excluded due to their significantly slower performance.

image

Notes

  • null performs no conversion and measures loop + call overhead.
  • sprintf and ostringstream do not generate shortest representations (e.g. 0.10.10000000000000001).
  • ryu, dragonbox, and schubfach always emit exponential notation (e.g. 0.11E-1).

Additional benchmark results are available in the results directory and viewable online using Google Charts:

Methods

Function Description
asteria rocket::ascii_numput::put_DD
double-conversion EcmaScriptConverter::ToShortest which implements Grisu3 with bignum fallback
dragonbox jkj::dragonbox::to_chars with full tables
fmt fmt::format_to with compile-time format strings (uses Dragonbox).
null no-op implementation
ostringstream std::ostringstream with setprecision(17)
ryu d2s_buffered
schubfach C++ Schubfach implementation
sprintf C sprintf("%.17g", value)
to_chars std::to_chars
zmij zmij::write.

Notes

std::to_string is excluded because it does not guarantee round-trip correctness (until C++26).

Why is fast dtoa important?

Floating-point formatting is ubiquitous in text output. Standard facilities such as sprintf and std::stringstream are often slow. This benchmark originated from performance work in RapidJSON.

See Also

About

C++ double-to-string conversion benchmark

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published