[Solved] Formatting Float64 using strconv/fmt

I’m wondering if this a limitation of strconv/fmt or if I’m misunderstanding something…

I’m looking to turn a float64 into a string. All my float64 fall well within the bounds of min and max
https://golang.org/pkg/math/#pkg-constants

However I’ve noticed something unusual (at least I think so), It happens when using fmt and strconv (strconv in example)
https://play.golang.org/p/0QF97RPCYB

My guess - I’ve misunderstood something. Perhaps I’m assuming the wrong max and min values. Or perhaps this is expected behaviour and I’m missing something.

If this is expected behaviour, why is it does strconv/fmt do this

Is there a way to change the func asString(f float) so that it works (works = nothing is printed because all strings match)?

oh - to give credit where credit is due I found the structure for the example
https://medium.com/@matryer/5-simple-tips-and-tricks-for-writing-unit-tests-in-golang-619653f90742
The example is based on the 4th tip.

Make sure you provide a way to easily figure out which test failed. Its also nicer when the expected and actual values are lined up so they are easier to compare.

To do this, I moved the comments you had for each test into a description field for the test. I also printed the expected and actual values on separate lines, using tab characters to line them up.

https://play.golang.org/p/RZqtcUL7JR

The value you used for max (253) is the largest integer-precision value that is supported by float64.

What you are missing is that float64 cannot represent every value. The next value after 9007199254740992 is 9007199254740994, not 9007199254740993. Use math.Nextafter to figure this out.

All of your failure cases make this same mistake (the number you specify can’t be represented exactly by float64). strconv.FormatFloat is behaving as specified:

The special precision -1 uses the smallest number of digits necessary such that ParseFloat will return f exactly.

f is just not what you think it is.

2 Likes

Thanks for the reply.

So the highest number in Go I can reliably transform into a string is 9007199254740992?
And anything over 17 digits also cannot reliably be transformed into a string?
Or is there another numeric type I could consider - from the looks of the docs there’s not.
https://golang.org/ref/spec#Numeric_types

I don’t have a use case for this - just interested :smiley:

I should clarify - I mean highest without using exponents.

According to wikipedia, 15 digits is the safe number (with a decimal between any of them or without a decimal). With FormatFloat this assumes there are no trailing zeros after the decimal.

After that it gets more complicated…

If you need larger numbers, then use math/big or an arbitrary precision decimal package.

Great. Thanks for the response. I’ve marked as solved now.

I don’t think math.big removes same issue seen with Float64 when converting to string (https://play.golang.org/p/AapyD4vxTC) - it seems that there is a cap of 9007199254740992 on out the box numeric types printing as a sting without exponent in Go. However a few of the linked arbitrary precision decimal packages might.

Thanks again.

1 Like

FWIW, this restriction is not specific to Go. The floating-point format IEEE 754 is a universal format and used across programming languages and even directly supported by hardware.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.