Skip to content
/ zmij Public

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

License

Notifications You must be signed in to change notification settings

vitaut/zmij

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🐉 Żmij

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
  • Fast compile time
  • IEEE 754 double and float support
  • Safer API than classic dtoa
  • 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];
  zmij::write(buf, sizeof(buf), 5.0507837461e-27);
  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):

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.

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

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.

  • 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.

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

About

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

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 8

Languages