Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR makes
Float64#to_s
produce a more correct output.This targets two issues: #2220 and #2643
The "correct" way to do it would be to use Dragon4 or some other well-known algorithm, as commented here. However, the algorithms are full of math that I don't want to learn right now, and code that is always implemented in C with a lot of lines of code full of defines and low-level hacks. We can probably do it, but later.
For now, I use
snprintf
with"%.17g"
, which produces a very good result but sometimes ends up with runs of zeros or nines. I check if there are such runs near the end of the string and remove them (case of zero) or replace them (case of nine, add one and carry). This makesFloat64#to_s
twice as slow, but still faster than Ruby:Ruby takes 0.95s, Crystal takes 0.77s with an argument "0.6337845278325672". It used to take 0.31s before this change. But, I don't think this is going to be a program's bottleneck, and for now I prefer a more accurate result than a faster but wrong one. I only compare it to Ruby because if it's slow but people use it, and in this case it's slightly faster, then it's still good (or "not that bad").
For Float32, the old algorithm is used (use
snprintf
with"%.g"
, first converting to Float64) because it seemssnprintf
doesn't handle floats. And Float32 is less used, so we can care of that later.An example of this change: