I can confirm your behaviour
ActivePython 2.6.4.10 (ActiveState Software Inc.) based on
Python 2.6.4 (r264:75706, Jan 22 2010, 17:24:21) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> repr(0.1)
'0.10000000000000001'
>>> repr(0.01)
'0.01'
Now, the docs claim that in Python <2.7
the value of repr(1.1)
was computed as format(1.1, '.17g')
This is a slight simplification.
Note that this is all to do with the string formatting code -- in memory, all Python floats are just stored as C++ doubles, so there is never going to be a difference between them.
Also, it's kind of unpleasant to work with the full-length string for a float even if you know that there's a better one. Indeed, in modern Pythons a new algorithm is used for float formatting, that picks the shortest representation in a smart way.
I spent a while looking this up in the source code, so I'll include the details here in case you're interested. You can skip this section.
In floatobject.c
, we see
static PyObject *
float_repr(PyFloatObject *v)
{
char buf[100];
format_float(buf, sizeof(buf), v, PREC_REPR);
return PyString_FromString(buf);
}
which leads us to look at format_float
. Omitting the NaN/inf special cases, it is:
format_float(char *buf, size_t buflen, PyFloatObject *v, int precision)
{
register char *cp;
char format[32];
int i;
/* Subroutine for float_repr and float_print.
We want float numbers to be recognizable as such,
i.e., they should contain a decimal point or an exponent.
However, %g may print the number as an integer;
in such cases, we append ".0" to the string. */
assert(PyFloat_Check(v));
PyOS_snprintf(format, 32, "%%.%ig", precision);
PyOS_ascii_formatd(buf, buflen, format, v->ob_fval);
cp = buf;
if (*cp == '-')
cp++;
for (; *cp != '\0'; cp++) {
/* Any non-digit means it's not an integer;
this takes care of NAN and INF as well. */
if (!isdigit(Py_CHARMASK(*cp)))
break;
}
if (*cp == '\0') {
*cp++ = '.';
*cp++ = '0';
*cp++ = '\0';
return;
}
<some NaN/inf stuff>
}
We can see that
So this first initialises some variables and checks that v
is a well-formed float. It then prepares a format string:
PyOS_snprintf(format, 32, "%%.%ig", precision);
Now PREC_REPR is defined elsewhere in floatobject.c
as 17, so this computes to "%.17g"
. Now we call
PyOS_ascii_formatd(buf, buflen, format, v->ob_fval);
With the end of the tunnel in sight, we look up PyOS_ascii_formatd
and discover that it uses snprintf
internally.