A simple solution to get a string representation of a float with full precision is to use json.dumps
.
JSON serialization/deserialization has to make sure that roundtrips are loss-less, and thus, the implementation produces a string representation you are looking for:
import json
def check(x,y):
print(json.dumps(x))
print(json.dumps(y))
print("x == y is {}".format(x == y))
In [1]: check(1.00000000000000001, 1.0000000000000002)
1.0
1.0000000000000002
x == y is False
In [2]: check(1e-300, 2e-300)
1e-300
2e-300
x == y is False
In [3]: check(1e+300, 2e+300)
1e+300
2e+300
x == y is False
This also clarifies that 1.00000000000000001
actually is 1.0. This can also be checked by enumerating the numbers around 1.0 using np.nextafter
, which produces the next larger/smaller representable floating point value:
0.9999999999999994
0.9999999999999996
0.9999999999999997
0.9999999999999998
0.9999999999999999
[*] 1.0
1.0000000000000002
1.0000000000000004
1.0000000000000007
1.0000000000000009
1.000000000000001
Another note: json.dumps
has a feature that in some cases can be annoying: It even supports NaN
and +/- infinite values even though they are not part of the JSON standard, which is actually beneficial in this use case.
An alternative I've seen is to use "{:.17g}".format(x)
based on the g format specifier. The formatter also switches from e
notation to fixed notation when necessary, and 17 digits should always be sufficient precision, but I haven't verified that. It can produce too many digits in some cases though.