I've been experimenting with parseFloat and I guess I'm already hitting its limits:
parseFloat("12312.12") # => 12312.12
parseFloat("12312.12123123456786708789878987123812739182739182739182739812739128739182731923") # => 12312.12123123457
How would you go about figuring out if a float can hold a given string value - that is, if it "overflow"s - or it's going to be truncated, before/after calling parseFloat?
it is not really a limit of parseFloat, it is a limit of float, which is not made for arbitrary long decimal numbers. In particular
echo 12312.12123123456786708789878987123812739182739182739182739812739128739182731923
# outputs 12312.12123123457
One way to make the check you ask could be to use bigints library and the incoming implementation for biggestFloat (still a PR for now) and use something like this (have not tested it):
func fitsInFloat(s: string): bool =
s.replace(".", "").initBigInt.toBiggestFloat == s.replace(".", "").parseFloat
there are likely more direct ways to do that.
I know it's about float`s. I'm just mentioning `parseFloat since I'm kind-of trying to make it behave as parseInt and throw an Overflow error if that is the case.
Basically, I'm working on Arturo and - given a weird error I've noticed - I'm trying to handle floating-point numbers/literals in a more efficient way. That is: if the number fits in a float, then fine. If not, we'll be using GMP's mpf_t (Arturo makes heavy use of the GMP library for bignums and extending it is not such a big deal): https://github.com/arturo-lang/arturo/pull/572
I'm having a look into what you suggested. Thanks! :)
the code shouldn't work, for once if you just strip the decimal point you can get such a big integer value that converted to double it will probably be Inf.
Ignoring those cases, I think a decimal number without the decimal point might fit or fit not a double, but then not fit or fit exactly with the decimal point inserted. Floats are binary and moving the decimal point is multiplying/dividing by ten, so the binary representation can change completely.
@drkameleon you're in luck though, because parseFloat handles the two cases you want to distinguish between separately: https://github.com/nim-lang/Nim/blob/394f4ac7bb92fe5aaf902495c6b43b3451667602/lib/system/strmantle.nim#L166
you are right there are a number of cases where the example function does not work. Also it would not have been appropriate given @drkamaleon's use case focusing on performance (why not directly using GMP's mpf_t?).
The code you shared is very interesting, the link that is there https://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ is also interesting.
Looking at the code (in particular this funny line) I was able to break compiler's float parsing (with a literal with more than 500 digits it starts falling apart): https://play.nim-lang.org/#ix=45P8
I guess it should be a bug to be reported.