If I run:
>>> import math
>>> print(math.pi)
3.141592653589793
Then pi is printed with 16 digits,
However, according to:
>>> import sys
>>> sys.float_info.dig
15
My precision is 15 digits.
So, should I rely on the last digit of that value (i.e. that the value of π indeed is 3.141592653589793nnnnnn).
TL;DR
The last digit of
str(float)
orrepr(float)
can be "wrong" in that it seems that the decimal representation is not correctly rounded.But that value is still closer to the original than
0.1000000000000000
(with 1 digit less).In the case of
math.pi
, the decimal approximation of pi is 3.141592653589793238463..., in this case the last digit is right.The
sys.float_info.dig
tells how many decimal digits are guaranteed to be always precise.The default output for both
str(float)
andrepr(float)
in Python 3.1+ (and 2.7 forrepr
) is the shortest string that when converted tofloat
will return the original value; in case of ambiguity, the last digit is rounded to the closest value. A float provides ~15.9 decimal digits of precision; but actually up to 17 decimal digit precision is required to represent a 53 binary digits unambiguously,For example
0.10000000000000004
is between0x1.999999999999dp-4
and0x1.999999999999cp-4
, but the latter is closer; these 2 have the decimal expansionsand
respectively. Clearly the latter is closer, so that binary representation is chosen.
Now when these are converted back to string with
str()
, orrepr()
, the shortest string that yields the exactly same value is chosen; for these 2 values they are0.10000000000000005
and0.10000000000000003
respectivelyThe precision of a
double
in IEEE-754 is 53 binary digits; in decimal you can calculate the precision by taking 10-based logarithm of 2^53,meaning almost 16 digits of precision. The
float_info
precision tells how much you can always expect to be presentable, and this number is 15, for there are some numbers with 16 decimal digits that are indistinguishable.However this is not the whole story. Internally what happens in Python 3.2+ is that the
float.__str__
andfloat.__repr__
end up calling the same C methodfloat_repr
:The
PyOS_double_to_string
then, for the'r'
mode (standing for repr), calls either the_Py_dg_dtoa
with mode 0, which is an internal routine to convert the double to a string, orsnprintf
with%17g
for those platforms for which the_Py_dg_dtoa
wouldn't work.The behaviour snprintf is entirely platform dependent, but if
_Py_dg_dtoa
is used (as far as I understand, it should be used on most machines), it should be predictable.The
_Py_dg_dtoa
mode 0 is specified as follows:So, that is what happens - the yielded string must exactly reproduce the
double
value when read in, and it must be the shortest representation possible, and among multiple decimal representations that would be read in, it would be the one that is closest to the binary value. Now, this might also mean that the last digit of decimal expansion does not match the original value rounded at that length, only that the decimal representation is as close to the original binary representation as possible. Thus YMMV.