Zmij: Faster floating point double-to-string conversion

vitaut.net

140 points by fanf2 4 days ago


floitsch - 18 hours ago

Pretty impressive.

When I published Grisu (Google double-conversion), it was multiple times faster than the existing algorithms. I knew that there was still room for improvement, but I was at most expecting a factor 2 or so. Six times faster is really impressive.

nhatcher - 2 hours ago

This blows my mind TBH. I used to say a few years back that Ryu is my favorite modern algorithm but it felt so complicated. Your C implentation almost feels... simple!

Congratulations, can't wait to have some time to study this further

amluto - 10 hours ago

I read the post and the companion post:

https://vitaut.net/posts/2025/smallest-dtoa/

And there’s one detail I found confusing. Suppose I go through the steps to find the rounding interval and determine that k=-3, so there is at most one integer multiple of 10^-3 in the interval (and at least one multiple of 10^-4). For the sake of argument, let’s say that -3 worked: m·10^-3 is in the interval.

Then, if m is not a multiple of 10, I believe that m·10^-3 is the right answer. But what if m is a multiple of 10? Then the result will be exactly equal, numerically, to the correct answer, but it will have trailing zeros. So maybe I get 7.460 instead of 7.46 (I made up this number and I have no idea whether any double exists gives this output.) Even though that 6 is definitely necessary (there is no numerically different value with decimal exponent greater than -3 that rounds correctly), I still want my formatter library to give me the shortest decimal representation of the result.

Is this impossible for some reason? Is there logic hiding in the write function to simplify the answer? Am I missing something?

HexDecOctBin - 14 hours ago

It seems that most research effort goes into better dtoa, and not enough in a better atod. There are probably a dozen dtoa algorithms now, and (I think?) two for atod. Anyone know why?

NovemberWhiskey - 14 hours ago

When I saw the title here, my first thought was “wow, these RISC-V ISA extensions are getting out of hand”

mulle_nat - 15 hours ago

Thank you for the code. I could port this easily to C and it solved a lot of portability issues for me.

andrepd - 17 hours ago

Very interesting!

I wonder how Teju Jaguá compares. I don't see it in the C++ benchmark repo you linked and whose graph you included.

I have contributed an implementation in Rust :) https://crates.io/crates/teju it includes benchmarks which compare it vs Ryu and vs Rust's stdlib, and the readme shows a graph with some test cases. It's quite easy to run if you're interested!

Cold_Miserable - 16 hours ago

Already done ages ago. Nothing more of interest.

The bottleneck are the 3 conditionals: - positive or negative - positive or negative exponent, x > 10.0 - correction for 1.xxxxx * 2^Y => fract(log10(2^Y)) 1.xxxxxxxx > 10.0