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 870.478 1.00x
sprintf 734.033 1.19x
double-conversion 82.903 10.50x
to_chars 42.537 20.46x
ryu 36.805 23.65x
schubfach 24.653 35.31x
fmt 22.201 39.21x
dragonbox 20.544 42.37x
yy 13.963 62.34x
xjb64 10.500 82.90x
zmij 8.895 97.87x
null 0.929 936.55x

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