> Often the problem is framed as "converting a floating point number to the shortest possible decimal string representation", but this framing is neither neccessary nor sufficient for implementing the %e / %f / %g formats of sprintf.
This sentence is crucial for anyone wants to implement the float-to-decimal conversion. There exists a Grisu-inspired analogue for this problem but to my current knowledge it is not well described in any known literature. I had to fully analyze the analogue and recreate my (slightly improved) version of the algorithm for Rust [1]. It is not too complex once you understood but annoying enough to derive again.
The end of the post alludes to part 2 ("how to adapt nd_print into something which can behave like the %e, %f, and %g formats of sprintf"), which alas I've yet to get around to writing. There'll also be at least one more part after that detailing the bag of performance tricks which can be used to turn the described algorithm into something very competitive. Alternatively, you can jump to the conclusion by just reading the implementation I wrote for LuaJIT [1], though obviously that won't give you the narrative of _why_ things are the way they are.
Starts with an int->string conversion, then does the rest with string manipulation - strings, of course, being bignums with a somewhat wasteful BCD representation.
Why are some converters more complicated than this? Because you can make them a little faster. On my laptop, glibc's sprintf(buf, "%.50e", M_PI) is about 15 times faster than an equivalent print using the code above, because the implementation of sprintf uses much more sophisticated mathematics to speed the conversion.
(When did he start writing articles in Go? IMHO the syntax is close enough to C to make skimming through easy enough, but confusing to look at in detail for the majority who will have likely far more experience with C than Go.)
In 1986 I did that in Turbo Pascal 3.0 for DOS. Had a bug with the round function so I made my own nround that converted the floating point to a string then parsed the string to find the right rounding and converted it back to a float. I was the only person in class to get the correct answer and graded down by my professor and accused of hacking.
I just have to whine that I have always hated the construct "convert to string".
You don't convert a car to a photograph when you take a picture, and neither do you do any "conversion" when you construct a string that represents the same value as is represented by the bit pattern of your double or float.
This sounds like some weird linguistic pedantry, and perhaps it is, but I suspect this usage causes confusion for a number of beginning programmers.
I think using "convert x to y" is linguistically okay as you're referring to a type conversion. Both x and y refer to objects which can be related to each other somehow. The same way a US plug adapter is used to convert a European plug to a American one.
To (almost) keep with the analogy, it's okay to say a car was converted to a picture if it was squashed to be almost flat, framed and hung on a wall somehow. Some type conversions are highly destructive whereas others are trivial, like converting a table to a desk.
To push the analogy even further I couldn't convert a car to a photograph exactly as the types are incompatable, like a float and an array (at least in most programming languages).
Isn't currency conversion something similar? The same value, in a different representation.
Disclaimer: I'm not a native speaker and have trouble differentiating between programming jargon and normal English. Sometimes I forget strings can also be made of yarn instead of text...
Its perfectly applicable when there is no data loss in the conversion. The string "93" and the byte 01011101 are just different representations of the same piece of data.
When there is data loss, I personally prefer the term "string representation"
This sentence is crucial for anyone wants to implement the float-to-decimal conversion. There exists a Grisu-inspired analogue for this problem but to my current knowledge it is not well described in any known literature. I had to fully analyze the analogue and recreate my (slightly improved) version of the algorithm for Rust [1]. It is not too complex once you understood but annoying enough to derive again.
[1] https://github.com/rust-lang/rust/blob/f8d485f/src/libcore/n...