SkillAgentSearch skills...

Zmij

A double-to-string conversion algorithm based on Schubfach and yy

Install / Use

/learn @vitaut/Zmij
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

🐉 Żmij

CI

A double-to-string conversion algorithm based on Schubfach and yy 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 size = zmij::write(buf, sizeof(buf), 5.0507837461e-27);
  buf[size] = '\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.

| Function | Time (ns) | Speedup | |-------------------|----------:|--------:| | ostringstream | 871.431 | 1.00x | | sprintf | 735.292 | 1.19x | | double-conversion | 83.332 | 10.46x | | to_chars | 42.808 | 20.36x | | ryu | 36.809 | 23.67x | | schubfach | 24.721 | 35.25x | | fmt | 22.224 | 39.21x | | dragonbox | 20.532 | 42.44x | | yy | 14.006 | 62.22x | | xjb64 | 10.542 | 82.66x | | zmij | 8.661 | 100.62x | | null | 0.946 | 921.13x |

Conversion time (smaller is better):

<img width="726" height="313" alt="image" src="https://github.com/user-attachments/assets/c36c95c6-52a1-42a9-880e-d7621112f7d9" />

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

<img width="739" height="605" alt="image" src="https://github.com/user-attachments/assets/e6452189-5a4c-4ba2-9e17-f720e263dd5d" />

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.

| Function | Time (ns) | Speedup | |---------------------|----------:|--------:| | ostringstream | 958.889 | 1.00x | | sprintf | 563.022 | 1.70x | | double-conversion | 95.706 | 10.02x | | to_chars | 67.115 | 14.29x | | ryu | 54.144 | 17.71x | | schubfach | 44.435 | 21.58x | | fmt | 40.098 | 23.91x | | dragonbox | 30.896 | 31.04x | | yy | 26.959 | 35.57x | | xjb64 | 19.275 | 49.75x | | zmij | 19.194 | 49.96x | | null | 2.766 | 346.72x |

<img width="741" height="327" alt="image" src="https://github.com/user-attachments/assets/e7f0ec3f-7317-4c60-b33d-c106215f1ee6" />

<img width="761" height="616" alt="image" src="https://github.com/user-attachments/assets/cece5726-006c-4712-bf09-6ca62c27ef29" />

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

  • C++: https://github.com/vitaut/zmij/blob/main/zmij.cc (reference implementation)
  • C: https://github.com/vitaut/zmij/blob/main/zmij.c
  • Rust: https://github.com/dtolnay/zmij
  • Zig: https://github.com/de-sh/zmij

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.

  • Cassio Neri (@cassioneri) - Proposed the single-candidate rounding strategy 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.

  • Russ Cox (@rsc) - Devised the simplified longer candidate selection for Schubfach adopted in Żmij's fallback path.

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

Related Skills

View on GitHub
GitHub Stars312
CategoryDevelopment
Updated23h ago
Forks20

Languages

C++

Security Score

100/100

Audited on Mar 23, 2026

No findings