While working with float precision, I stumbled across a strange fact. Why does python prints only the integer part when formatted with "%.f"
. I am willing to know the mechanism behind this
>>> a = float(2.12345)
>>> a
2.12345
>>> print "%.2f" % a
2.12
>>> print "%.1f" % a
2.1
>>> print "%f" % a
2.123450
>>> print "%.f" % a
2 #why?
Thanks in advance for the explanation :)
2f means to round up to two decimal places. You can play around with the code to see what happens as you change the number in the formatter.
In Python, to print 2 decimal places we will use str. format() with “{:. 2f}” as string and float as a number. Call print and it will print the float with 2 decimal places.
Python 3's float repr is designed to be round-trippable, that is, the value shown should be exactly convertible into the original value ( float(repr(f)) == f for all floats f ). Therefore, it cannot display 0.3 and 0.1*3 exactly the same way, or the two different numbers would end up the same after round-tripping.
It's been that way ever since %
formatting was added back in 1993; if a .
is not followed by a decimal number then precision is taken as zero.
This is undocumented, but is consistent with printf
, which Python's %
formatting was inspired by:
(optional)
.
followed by integer number or*
, or neither that specifies precision of the conversion. In the case when*
is used, the precision is specified by an additional argument of type int. If the value of this argument is negative, it is ignored. If neither a number nor*
is used, the precision is taken as zero.
Interestingly, another undocumented feature also inspired by printf
is that you can use *
as precision, as above:
>>> "%6.*f" % (2, 1.234)
' 1.23'
The docs for precision here don't mention a default if the precision is ommitted. I can only assume it just works this way because it does!
The docs give the default precision for a %f as 6 in the format specification mini language here. Maybe by specifying a precision with the . and then by omitting an integer value, the interpreter assumes it should be zero?
This may even behave differently on different interpreters. Interesting find anyway :).
Interestingly, using str.format throws a nice ValueError in my 2.7 interpreter:
>>> f = 234.12345676
>>> "{:.f}".format(f)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: Format specifier missing precision
The %
operator has the following behavior, like you observed:
>>> "%.f" % 1.23
'1'
The parser goes through the format string, with the precision being undefined (-1
) by default. When it hits the .
, the precision will be set to 0
. The arguments will be passed to the helper function formatfloat
which uses the default precision 6
if no precision is given, and no .
is used.
An interesting note is that str.format() will actually throw an exception in this case, probably for easier implementation and not letting people rely on unspecified behavior:
>>> "{:.f}".format(1.23)
Traceback (most recent call last):
File "<ipython-input-6-677ba2e4a680>", line 1, in <module>
"{:.f}".format(1.23)
ValueError: Format specifier missing precision
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With