🐉 Żmij

April 19, 2026 · View on GitHub

CI

A double-to-string conversion algorithm based on Schubfach and xjb with implementations in C and C++

Features

  • Round trip guarantee
  • Shortest decimal representation
  • Correct rounding
  • High performance
  • Small binary size
  • Fast compile time
  • IEEE 754 double and float support
  • Safer API than classic dtoa
  • User-friendly output format similar to Python's default representation
  • Negative zero dependencies
  • Small, clean codebase consisting of one source file and an optional header
  • Permissive license

Usage

#include "zmij.h"
#include <stdio.h>

int main() {
  char buf[zmij::double_buffer_size + 1];
  auto end = zmij::write(buf, sizeof(buf), 5.0507837461e-27);
  *end = '\0';
  puts(buf);
}

Performance

Żmij v1 is more than 4x faster than Ryū used by multiple C++ standard library implementations, 9x faster than double-conversion and ~2.5x faster than Schubfach on dtoa-benchmark run on Apple M1.

FunctionTime (ns)Speedup
ostringstream871.4311.00x
sprintf735.2921.19x
double-conversion83.33210.46x
to_chars42.80820.36x
ryu36.80923.67x
schubfach24.72135.25x
fmt22.22439.21x
dragonbox20.53242.44x
yy14.00662.22x
xjb6410.54282.66x
zmij8.661100.62x
null0.946921.13x

Conversion time (smaller is better):

image

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

image

On EPYC Milan (AMD64) running Linux, Żmij is approximately 2.8× faster than Ryū and 5× faster than double-conversion when compiled with GCC 11.5.

FunctionTime (ns)Speedup
ostringstream958.8891.00x
sprintf563.0221.70x
double-conversion95.70610.02x
to_chars67.11514.29x
ryu54.14417.71x
schubfach44.43521.58x
fmt40.09823.91x
dragonbox30.89631.04x
yy26.95935.57x
xjb6419.27549.75x
zmij19.19449.96x
null2.766346.72x

image

image

Compile time

Compile time is ~135ms by default and ~180ms with optimizations enabled as measured by

% time c++ -c zmij.cc [-O2]

taking the best of 3 runs.

Languages

Differences from Schubfach

  • 1 instead of 3 multiplications by a power of 10 in the common case
  • Faster logarithm approximations
  • Faster division and modulo
  • Fewer conditional branches
  • More efficient significand and exponent output
  • Improved storage of powers of 10
  • SIMD support

Name

Żmij (pronounced roughly zhmeey or more precisely /ʐmij/) is a Polish word that refers to a mythical dragon- or serpent-like creature, continuing the dragon theme started by Steele and White.

A nice bonus is that the name even contains a "floating point" in its first letter. And to quote Aras Pranckevičius, "Żmij is also literally a beast."

Acknowledgements

We would like to express our gratitude to the individuals who have made Żmij possible:

  • Victor Zverovich (@vitaut) - Original author and maintainer of Żmij.

  • Tobias Schlüter (@TobiSchluter) - Contributed significant performance and portability improvements, including SIMD/SSE support and core algorithm refinements that enhance execution speed and cross-platform compatibility.

  • Dougall Johnson (@dougallj) – Authored the NEON implementation and contributed many optimization ideas, substantially improving performance on ARM platforms.

  • Alex Guteniev (@AlexGuteniev) - Contributed multiple fixes and improvements across build systems, platform compatibility, and testing infrastructure.

  • Xiang JunBo (@xjb714) - Contributed high-performance BCD digit extraction algorithm and additional optimization ideas used across scalar and SIMD code paths. The double path uses xjb's $10^{-k-1}$ scaling to eliminate a division from the critical path.

  • David Tolnay (@dtolnay) - Created and maintains the Rust port of Żmij, expanding the algorithm's reach and adoption in the Rust ecosystem.

  • Raffaello Giulietti - Author of the Schubfach algorithm, whose work forms a foundational basis for Żmij.

  • Yaoyuan Guo (@ibireme) - Author of the yy algorithm, whose ideas influenced key optimizations used in Żmij.

  • Junekey Jeon (@jk-jeon) - Author of the Dragonbox algorithm, which informed design and benchmarking comparisons for Żmij, as well as the to_decimal API.

  • Community contributors who provided feedback, issues, suggestions, and occasional commits, helping improve the robustness and performance of Żmij.